| @ -0,0 +1,123 @@ | |||
| -- ASDL's six builtin types are identifier, int, string, bytes, object, singleton | |||
| module Python | |||
| { | |||
| mod = Module(stmt* body) | |||
| | Interactive(stmt* body) | |||
| | Expression(expr body) | |||
| -- not really an actual node but useful in Jython's typesystem. | |||
| | Suite(stmt* body) | |||
| stmt = FunctionDef(identifier name, arguments args, | |||
| stmt* body, expr* decorator_list, expr? returns) | |||
| | AsyncFunctionDef(identifier name, arguments args, | |||
| stmt* body, expr* decorator_list, expr? returns) | |||
| | ClassDef(identifier name, | |||
| expr* bases, | |||
| keyword* keywords, | |||
| stmt* body, | |||
| expr* decorator_list) | |||
| | Return(expr? value) | |||
| | Delete(expr* targets) | |||
| | Assign(expr* targets, expr value) | |||
| | AugAssign(expr target, operator op, expr value) | |||
| -- use 'orelse' because else is a keyword in target languages | |||
| | For(expr target, expr iter, stmt* body, stmt* orelse) | |||
| | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse) | |||
| | While(expr test, stmt* body, stmt* orelse) | |||
| | If(expr test, stmt* body, stmt* orelse) | |||
| | With(withitem* items, stmt* body) | |||
| | AsyncWith(withitem* items, stmt* body) | |||
| | Raise(expr? exc, expr? cause) | |||
| | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) | |||
| | Assert(expr test, expr? msg) | |||
| | Import(alias* names) | |||
| | ImportFrom(identifier? module, alias* names, int? level) | |||
| | Global(identifier* names) | |||
| | Nonlocal(identifier* names) | |||
| | Expr(expr value) | |||
| | Pass | Break | Continue | |||
| -- XXX Jython will be different | |||
| -- col_offset is the byte offset in the utf8 string the parser uses | |||
| attributes (int lineno, int col_offset) | |||
| -- BoolOp() can use left & right? | |||
| expr = BoolOp(boolop op, expr* values) | |||
| | BinOp(expr left, operator op, expr right) | |||
| | UnaryOp(unaryop op, expr operand) | |||
| | Lambda(arguments args, expr body) | |||
| | IfExp(expr test, expr body, expr orelse) | |||
| | Dict(expr* keys, expr* values) | |||
| | Set(expr* elts) | |||
| | ListComp(expr elt, comprehension* generators) | |||
| | SetComp(expr elt, comprehension* generators) | |||
| | DictComp(expr key, expr value, comprehension* generators) | |||
| | GeneratorExp(expr elt, comprehension* generators) | |||
| -- the grammar constrains where yield expressions can occur | |||
| | Await(expr value) | |||
| | Yield(expr? value) | |||
| | YieldFrom(expr value) | |||
| -- need sequences for compare to distinguish between | |||
| -- x < 4 < 3 and (x < 4) < 3 | |||
| | Compare(expr left, cmpop* ops, expr* comparators) | |||
| | Call(expr func, expr* args, keyword* keywords) | |||
| | Num(object n) -- a number as a PyObject. | |||
| | Str(string s) -- need to specify raw, unicode, etc? | |||
| | Bytes(bytes s) | |||
| | NameConstant(singleton value) | |||
| | Ellipsis | |||
| -- the following expression can appear in assignment context | |||
| | Attribute(expr value, identifier attr, expr_context ctx) | |||
| | Subscript(expr value, slice slice, expr_context ctx) | |||
| | Starred(expr value, expr_context ctx) | |||
| | Name(identifier id, expr_context ctx) | |||
| | List(expr* elts, expr_context ctx) | |||
| | Tuple(expr* elts, expr_context ctx) | |||
| -- col_offset is the byte offset in the utf8 string the parser uses | |||
| attributes (int lineno, int col_offset) | |||
| expr_context = Load | Store | Del | AugLoad | AugStore | Param | |||
| slice = Slice(expr? lower, expr? upper, expr? step) | |||
| | ExtSlice(slice* dims) | |||
| | Index(expr value) | |||
| boolop = And | Or | |||
| operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | |||
| | RShift | BitOr | BitXor | BitAnd | FloorDiv | |||
| unaryop = Invert | Not | UAdd | USub | |||
| cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn | |||
| comprehension = (expr target, expr iter, expr* ifs) | |||
| excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) | |||
| attributes (int lineno, int col_offset) | |||
| arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, | |||
| arg? kwarg, expr* defaults) | |||
| arg = (identifier arg, expr? annotation) | |||
| attributes (int lineno, int col_offset) | |||
| -- keyword arguments supplied to call (NULL identifier for **kwargs) | |||
| keyword = (identifier? arg, expr value) | |||
| -- import name with optional 'as' alias. | |||
| alias = (identifier name, identifier? asname) | |||
| withitem = (expr context_expr, expr? optional_vars) | |||
| } | |||
| @ -0,0 +1,42 @@ | |||
| package ast | |||
| import "fmt" | |||
| type Expression interface { | |||
| Node | |||
| expr() | |||
| } | |||
| type Name struct { | |||
| Identifier string | |||
| Context ExpressionContext | |||
| } | |||
| func NewName(id string, ctx ExpressionContext) *Name { | |||
| return &Name{ | |||
| Identifier: id, | |||
| Context: ctx, | |||
| } | |||
| } | |||
| func (name *Name) node() {} | |||
| func (name *Name) expr() {} | |||
| func (name *Name) String() string { | |||
| return fmt.Sprintf("Name(id=%#v, ctx=%s)", name.Identifier, name.Context.String()) | |||
| } | |||
| type Num struct { | |||
| Value int64 | |||
| } | |||
| func NewNum(i int64) *Num { | |||
| return &Num{ | |||
| Value: i, | |||
| } | |||
| } | |||
| func (num *Num) node() {} | |||
| func (num *Num) expr() {} | |||
| func (num *Num) String() string { | |||
| return fmt.Sprintf("Num(n=%d)", num.Value) | |||
| } | |||
| @ -0,0 +1,26 @@ | |||
| package ast | |||
| type ExpressionContext interface { | |||
| Node | |||
| exprCtx() | |||
| } | |||
| type Store struct{} | |||
| func NewStore() *Store { | |||
| return &Store{} | |||
| } | |||
| func (store *Store) node() {} | |||
| func (store *Store) exprCtx() {} | |||
| func (store *Store) String() string { return "Store()" } | |||
| type Load struct{} | |||
| func NewLoad() *Load { | |||
| return &Load{} | |||
| } | |||
| func (load *Load) node() {} | |||
| func (load *Load) exprCtx() {} | |||
| func (load *Load) String() string { return "Load()" } | |||
| @ -0,0 +1,34 @@ | |||
| package ast | |||
| import ( | |||
| "fmt" | |||
| "strings" | |||
| ) | |||
| type Mod interface { | |||
| Node | |||
| mod() | |||
| } | |||
| type Module struct { | |||
| Body []Statement | |||
| } | |||
| func NewModule() *Module { | |||
| return &Module{ | |||
| Body: make([]Statement, 0), | |||
| } | |||
| } | |||
| func (module *Module) node() {} | |||
| func (module *Module) mod() {} | |||
| func (module *Module) Append(stmt Statement) { | |||
| module.Body = append(module.Body, stmt) | |||
| } | |||
| func (module *Module) String() string { | |||
| stmts := make([]string, 0) | |||
| for _, stmt := range module.Body { | |||
| stmts = append(stmts, stmt.String()) | |||
| } | |||
| return fmt.Sprintf("Module(body=[%s])", strings.Join(stmts, ", ")) | |||
| } | |||
| @ -0,0 +1,6 @@ | |||
| package ast | |||
| type Node interface { | |||
| node() | |||
| String() string | |||
| } | |||
| @ -0,0 +1,196 @@ | |||
| package ast | |||
| import ( | |||
| "fmt" | |||
| "strconv" | |||
| "github.com/brettlangdon/gython/grammar" | |||
| "github.com/brettlangdon/gython/symbol" | |||
| "github.com/brettlangdon/gython/token" | |||
| ) | |||
| func ASTFromGrammar(root *grammar.FileInput) (Mod, error) { | |||
| mod := NewModule() | |||
| for _, child := range root.Children() { | |||
| if child.ID() == symbol.STMT { | |||
| stmt := astForStatement(child.(*grammar.Statement)) | |||
| mod.Append(stmt) | |||
| } | |||
| } | |||
| return mod, nil | |||
| } | |||
| func isToken(node grammar.Node, tokId token.TokenID) bool { | |||
| if n, isTokenNode := node.(*grammar.TokenNode); isTokenNode { | |||
| return n.Token.ID == tokId | |||
| } | |||
| return false | |||
| } | |||
| func astForStatement(root *grammar.Statement) Statement { | |||
| stmt := root.Child() | |||
| if stmt.ID() == symbol.SIMPLE_STMT { | |||
| stmt = stmt.(*grammar.SimpleStatement).Children()[0] | |||
| } | |||
| switch stmt := stmt.(type) { | |||
| case *grammar.SmallStatement: | |||
| switch child := stmt.Child().(type) { | |||
| case *grammar.ExpressionStatement: | |||
| return astForExpressionStatement(child) | |||
| } | |||
| case *grammar.CompoundStatement: | |||
| fmt.Println(stmt) | |||
| } | |||
| return nil | |||
| } | |||
| func astForExpressionStatement(root *grammar.ExpressionStatement) Statement { | |||
| children := root.Children() | |||
| if len(children) == 1 { | |||
| } else if "todo" == "augassign" { | |||
| } else { | |||
| if !isToken(children[1], token.EQUAL) { | |||
| return nil | |||
| } | |||
| length := len(children) | |||
| var value Expression | |||
| switch child := children[length-1].(type) { | |||
| case *grammar.TestlistStarExpression: | |||
| value = astForTestList(child) | |||
| default: | |||
| value = nil | |||
| } | |||
| assign := NewAssign(value) | |||
| for i := 0; i < length-2; i++ { | |||
| target := astForTestList(children[i].(grammar.ExpressionStatementChild)) | |||
| switch target := target.(type) { | |||
| case *Name: | |||
| target.Context = NewStore() | |||
| } | |||
| assign.Append(target) | |||
| } | |||
| return assign | |||
| } | |||
| return nil | |||
| } | |||
| func astForTestList(root grammar.ExpressionStatementChild) Expression { | |||
| switch root := root.(type) { | |||
| case *grammar.TestlistStarExpression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func astForExpression(root grammar.Node) Expression { | |||
| switch root := root.(type) { | |||
| case *grammar.Test: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.OrTest: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.AndTest: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.NotTest: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.Comparison: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.Expression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.XorExpression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.AndExpression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.ShiftExpression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.ArithmeticExpression: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.Term: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.Factor: | |||
| if root.Length() == 1 { | |||
| return astForExpression(root.Children()[0]) | |||
| } | |||
| case *grammar.Power: | |||
| return astForPower(root) | |||
| default: | |||
| fmt.Println(symbol.SymbolNames[root.ID()]) | |||
| } | |||
| return nil | |||
| } | |||
| func astForPower(root *grammar.Power) Expression { | |||
| children := root.Children() | |||
| var expr Expression | |||
| if child, isAtomExpr := children[0].(*grammar.AtomExpression); isAtomExpr { | |||
| expr = astForAtomExpression(child) | |||
| } else { | |||
| return nil | |||
| } | |||
| if len(children) == 1 { | |||
| return expr | |||
| } | |||
| return nil | |||
| } | |||
| func astForAtomExpression(root *grammar.AtomExpression) Expression { | |||
| children := root.Children() | |||
| switch child := children[0].(type) { | |||
| case *grammar.Atom: | |||
| return astForAtom(child) | |||
| } | |||
| return nil | |||
| } | |||
| func astForAtom(root *grammar.Atom) Expression { | |||
| children := root.Children() | |||
| if len(children) == 1 { | |||
| switch child := children[0].(type) { | |||
| case *grammar.TokenNode: | |||
| switch child.Token.ID { | |||
| case token.NAME: | |||
| // TODO: Check for "None", "True", and "False" | |||
| return NewName(child.Token.Literal, NewLoad()) | |||
| case token.NUMBER: | |||
| value, err := strconv.ParseInt(child.Token.Literal, 10, 64) | |||
| if err != nil { | |||
| return nil | |||
| } | |||
| return NewNum(value) | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @ -0,0 +1,37 @@ | |||
| package ast | |||
| import ( | |||
| "fmt" | |||
| "strings" | |||
| ) | |||
| type Statement interface { | |||
| Node | |||
| stmt() | |||
| } | |||
| type Assign struct { | |||
| Targets []Expression | |||
| Value Expression | |||
| } | |||
| func NewAssign(value Expression) *Assign { | |||
| return &Assign{ | |||
| Targets: make([]Expression, 0), | |||
| Value: value, | |||
| } | |||
| } | |||
| func (assign *Assign) node() {} | |||
| func (assign *Assign) stmt() {} | |||
| func (assign *Assign) Append(target Expression) { | |||
| assign.Targets = append(assign.Targets, target) | |||
| } | |||
| func (assign *Assign) String() string { | |||
| exprs := make([]string, 0) | |||
| for _, expr := range assign.Targets { | |||
| exprs = append(exprs, expr.String()) | |||
| } | |||
| return fmt.Sprintf("Assign(targets=[%s], value=%s)", strings.Join(exprs, ", "), assign.Value.String()) | |||
| } | |||