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 }