forked from flashcat/categraf
140 lines
3.2 KiB
Go
140 lines
3.2 KiB
Go
// Copyright 2011 Google Inc. All Rights Reserved.
|
|
// This file is available under the Apache license.
|
|
|
|
package compiler
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"path/filepath"
|
|
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/code"
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/compiler/ast"
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/compiler/checker"
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/compiler/codegen"
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/compiler/opt"
|
|
"flashcat.cloud/categraf/inputs/mtail/internal/runtime/compiler/parser"
|
|
// "github.com/golang/glog"
|
|
)
|
|
|
|
type Compiler struct {
|
|
emitAst bool
|
|
emitAstTypes bool
|
|
maxRegexpLength int
|
|
maxRecursionDepth int
|
|
disableOptimisation bool
|
|
}
|
|
|
|
func New(options ...Option) (*Compiler, error) {
|
|
c := &Compiler{}
|
|
if err := c.SetOption(options...); err != nil {
|
|
return nil, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func (c *Compiler) SetOption(options ...Option) error {
|
|
for _, option := range options {
|
|
if err := option(c); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Option configures a new Compiler.
|
|
type Option func(*Compiler) error
|
|
|
|
// EmitAst emits the AST after the parse phase.
|
|
func EmitAst() Option {
|
|
return func(c *Compiler) error {
|
|
c.emitAst = true
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// EmitAstTypes emits the AST with types after the type checking phase.
|
|
func EmitAstTypes() Option {
|
|
return func(c *Compiler) error {
|
|
c.emitAstTypes = true
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// MaxRegexpLength sets the maximum allowable length of a regular expression.
|
|
func MaxRegexpLength(maxRegexpLength int) Option {
|
|
return func(c *Compiler) error {
|
|
c.maxRegexpLength = maxRegexpLength
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// MaxRecursionDepth sets the maximum allowable depth of the AST.
|
|
func MaxRecursionDepth(maxRecursionDepth int) Option {
|
|
return func(c *Compiler) error {
|
|
c.maxRecursionDepth = maxRecursionDepth
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// DisableOptimisation disables the optimisation phase.
|
|
func DisableOptimisation() Option {
|
|
return func(c *Compiler) error {
|
|
c.disableOptimisation = true
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Compile compiles a program from the input into bytecode and data stored in an Object, or a list
|
|
// of compile errors.
|
|
func (c *Compiler) Compile(name string, input io.Reader) (obj *code.Object, err error) {
|
|
name = filepath.Base(name)
|
|
|
|
var ast ast.Node
|
|
|
|
ast, err = parser.Parse(name, input)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if c.emitAst {
|
|
s := parser.Sexp{}
|
|
log.Printf("%s AST:\n%s", name, s.Dump(ast))
|
|
}
|
|
|
|
if !c.disableOptimisation {
|
|
ast, err = opt.Optimise(ast)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if c.emitAstTypes {
|
|
s := parser.Sexp{}
|
|
log.Printf("Post optimisation %s AST:\n%s", name, s.Dump(ast))
|
|
}
|
|
}
|
|
|
|
ast, err = checker.Check(ast, c.maxRegexpLength, c.maxRecursionDepth)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if c.emitAstTypes {
|
|
s := parser.Sexp{}
|
|
s.EmitTypes = true
|
|
log.Printf("%s AST with Type Annotation:\n%s", name, s.Dump(ast))
|
|
}
|
|
|
|
if !c.disableOptimisation {
|
|
ast, err = opt.Optimise(ast)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if c.emitAstTypes {
|
|
s := parser.Sexp{}
|
|
s.EmitTypes = true
|
|
log.Printf("Post optimisation %s AST with Type Annotation:\n%s", name, s.Dump(ast))
|
|
}
|
|
}
|
|
|
|
obj, err = codegen.CodeGen(name, ast)
|
|
return
|
|
}
|