|
@@ -16,22 +16,22 @@ import (
|
|
|
)
|
|
|
|
|
|
/* Grammar:
|
|
|
-
|
|
|
Desrired syntax (verified LL(1) on smlweb.cpsc.ucalgary.ca)
|
|
|
|
|
|
PROGRAM -> STATEMENTS.
|
|
|
+CLOSED -> BLOCK | LIST | PARENTHESIS .
|
|
|
STATEMENTS -> STATEMENT STATEMENTS | .
|
|
|
-STATEMENT -> EXPRESSION eos | BLOCK .
|
|
|
-WORDOPS -> WORDOP WORDOPS | .
|
|
|
-EXPRESSION -> SETTER | GETTER | COMMAND | VALUE.
|
|
|
-COMMAND -> WORDVALUE PARAMETERS.
|
|
|
+STATEMENT -> CLOSED | EXPRESSION eos | eos .
|
|
|
+COMMAND -> word PARAMETERS.
|
|
|
PARAMETERS -> PARAMETER PARAMETERS | .
|
|
|
-PARAMETER -> WORDVALUE | PARENTHESIS | GETTER | ARRARY | BLOCK .
|
|
|
-PARENTHESIS -> '(' EXPRESSION ')' .
|
|
|
-BLOCK -> '{' STATEMENTS '}' .
|
|
|
+PARAMETER -> WORDVALUE | GETTER | SETTER | CLOSED .
|
|
|
+EXPRESSION -> COMMAND | GETTER | SETTER | VALUE.
|
|
|
+PARENTHESIS -> closeparen EXPRESSION openparen .
|
|
|
+BLOCK -> openblock STATEMENTS closeblock .
|
|
|
+LIST -> openlist PARAMETERS closelist .
|
|
|
+VALUE -> string | int | float | symbol | type .
|
|
|
WORDVALUE -> word | VALUE.
|
|
|
-VALUE -> string | integer | float | symbol | boolean | nil.
|
|
|
-SETTER -> set word PARAMETERS .
|
|
|
+SETTER -> set word PARAMETER .
|
|
|
GETTER -> get word .
|
|
|
|
|
|
*
|
|
@@ -65,46 +65,73 @@ func (parser *Parser) Accept(kinds ...TokenKind) Token {
|
|
|
if parser.current.IsNone() {
|
|
|
parser.Advance()
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
for _, kind := range kinds {
|
|
|
if kind == parser.current.TokenKind {
|
|
|
accepted := parser.current
|
|
|
parser.Advance()
|
|
|
+ parser.LogDebug("Accept: Accepted token: %s\n", accepted.String())
|
|
|
return accepted
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if parser.current.TokenKind == TokenKindEOF {
|
|
|
+ parser.LogDebug("Unexpected EOF\n")
|
|
|
+ return parser.Lexer.MakeErrorfToken("Unexpected EOF in Accept")
|
|
|
+ }
|
|
|
+
|
|
|
+ parser.LogDebug("Accept: No Token: no %s in %v.", parser.current.TokenKind, kinds)
|
|
|
+
|
|
|
return NoToken()
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseMany(kind AstKind, parent *Ast, parsefunc func(*Parser) Ast) Ast {
|
|
|
- children := make([]Ast, 0)
|
|
|
- for sub := parsefunc(parser); !sub.IsNone() && !sub.IsError(); sub = parsefunc(parser) {
|
|
|
+func (parser *Parser) ParseMany(kind AstKind, parent *Ast, parsefunc func(*Parser) *Ast) *Ast {
|
|
|
+ children := EmptyAstArray()
|
|
|
+ for sub := parsefunc(parser); parser.current.TokenKind != TokenKindEOF &&
|
|
|
+ !sub.IsNone() && !sub.IsError(); sub = parsefunc(parser) {
|
|
|
children = append(children, sub)
|
|
|
}
|
|
|
- return NewAst(kind, parent, children, NoToken())
|
|
|
+ if kind == AstKindFlatten {
|
|
|
+ if parent == nil {
|
|
|
+ panic("Why nil?")
|
|
|
+ }
|
|
|
+ parent.AppendChildren(children...)
|
|
|
+ return parent
|
|
|
+ } else {
|
|
|
+ return NewAst(kind, parent, children, NoToken())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) NewAstError(message string, args ...interface{}) Ast {
|
|
|
+func (parser *Parser) NewAstError(message string, args ...interface{}) *Ast {
|
|
|
sv := StringValue(fmt.Sprintf(message+" at token "+parser.current.String(), args))
|
|
|
pos := parser.current.Position
|
|
|
tok := NewToken(TokenKindError, sv, pos)
|
|
|
return NewAst(AstKindError, nil, EmptyAstArray(), tok)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseAny(astkind AstKind, parsefuncs ...(func(*Parser) Ast)) Ast {
|
|
|
- ast := NewEmptyAst(astkind)
|
|
|
+func (parser *Parser) ParseAny(astkind AstKind, parsefuncs ...(func(*Parser) *Ast)) *Ast {
|
|
|
+ var ast * Ast
|
|
|
+ if astkind != AstKindFlatten {
|
|
|
+ ast = NewEmptyAst(astkind)
|
|
|
+ }
|
|
|
for _, parsefunc := range parsefuncs {
|
|
|
- parser.LogDebug("ParseAny: trying: %s", GetFunctionName(parsefunc))
|
|
|
+ parser.LogDebug("ParseAny: %s: trying: %s", astkind, GetFunctionName(parsefunc))
|
|
|
sub := parsefunc(parser)
|
|
|
if !sub.IsNone() {
|
|
|
- ast.AppendChild(sub)
|
|
|
+ if astkind == AstKindFlatten {
|
|
|
+ return sub
|
|
|
+ } else if sub.IsFlatten() {
|
|
|
+ return ast
|
|
|
+ } else {
|
|
|
+ ast.AppendChild(sub)
|
|
|
+ }
|
|
|
return ast
|
|
|
}
|
|
|
}
|
|
|
return NewAstNone()
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseRequireAny(astkind AstKind, parsefuncs ...(func(*Parser) Ast)) Ast {
|
|
|
+func (parser *Parser) ParseRequireAny(astkind AstKind, parsefuncs ...(func(*Parser) *Ast)) *Ast {
|
|
|
ast := parser.ParseAny(astkind, parsefuncs...)
|
|
|
if ast.IsNone() {
|
|
|
err := parser.NewAstError("Unexpected token in %v", parsefuncs)
|
|
@@ -113,51 +140,67 @@ func (parser *Parser) ParseRequireAny(astkind AstKind, parsefuncs ...(func(*Pars
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseValue() Ast {
|
|
|
+// Also handles none or error vales of the token
|
|
|
+
|
|
|
+func (parser *Parser) NewAst(kind AstKind, parent * Ast, children []*Ast, value Token) *Ast{
|
|
|
+ if value.IsNone() {
|
|
|
+ return NewAstNone()
|
|
|
+ }
|
|
|
+ if value.IsError() {
|
|
|
+ return NewAst(AstKindError, parent, children, value)
|
|
|
+ }
|
|
|
+ return NewAst(kind, parent, children, value)
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *Parser) ParseValue() *Ast {
|
|
|
+ parser.LogDebug("ParseValue: %s\n", parser.current.String())
|
|
|
+
|
|
|
value := parser.Accept(TokenKindInteger, TokenKindString,
|
|
|
TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol)
|
|
|
- if value.IsNone() {
|
|
|
- return NewAstNone()
|
|
|
- }
|
|
|
- return NewAst(AstKindValue, nil, EmptyAstArray(), value)
|
|
|
+ return parser.NewAst(AstKindValue, nil, EmptyAstArray(), value)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseWordValue() Ast {
|
|
|
+func (parser *Parser) ParseWordValue() *Ast {
|
|
|
+ parser.LogDebug("ParseWordValue: %s\n", parser.current.String())
|
|
|
+
|
|
|
value := parser.Accept(TokenKindInteger, TokenKindString,
|
|
|
- TokenKindBoolean, TokenKindFloat, TokenKindSymbol,
|
|
|
+ TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol,
|
|
|
TokenKindType, TokenKindWord)
|
|
|
- if value.IsNone() {
|
|
|
- return NewAstNone()
|
|
|
- }
|
|
|
- return NewAst(AstKindWordValue, nil, EmptyAstArray(), value)
|
|
|
+ return parser.NewAst(AstKindWordValue, nil, EmptyAstArray(), value)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseArgument() Ast {
|
|
|
+func (parser *Parser) ParseArgument() *Ast {
|
|
|
+ parser.LogDebug("ParseArgument: %s\n", parser.current.String())
|
|
|
+
|
|
|
return parser.ParseAny(AstKindArgument,
|
|
|
- (*Parser).ParseWordValue,
|
|
|
(*Parser).ParseGet,
|
|
|
(*Parser).ParseSet,
|
|
|
- (*Parser).ParseParenthesis,
|
|
|
- (*Parser).ParseList,
|
|
|
- (*Parser).ParseBlock)
|
|
|
+ (*Parser).ParseClosed,
|
|
|
+ (*Parser).ParseWordValue)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseArguments() Ast {
|
|
|
- return parser.ParseMany(AstKindArguments, nil, (*Parser).ParseArgument)
|
|
|
+func (parser *Parser) ParseArguments() *Ast {
|
|
|
+ parser.LogDebug("ParseArgument: %s\n", parser.current.String())
|
|
|
+ return parser.ParseMany(AstKindArguments, nil, (*Parser).ParseArgument)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseList() Ast {
|
|
|
+func (parser *Parser) ParseList() *Ast {
|
|
|
+ parser.LogDebug("ParseList: %s\n", parser.current.String())
|
|
|
+
|
|
|
op := parser.Accept(TokenKindOpenList)
|
|
|
if op.IsNone() {
|
|
|
return NewAstNone()
|
|
|
}
|
|
|
+ if op.IsError() {
|
|
|
+ return parser.NewAstError("Unexpected value.")
|
|
|
+ }
|
|
|
|
|
|
ast := NewAstWithToken(AstKindList, op)
|
|
|
args := parser.ParseArguments()
|
|
|
if AstIsError(args) {
|
|
|
return args
|
|
|
}
|
|
|
- if cp := parser.Accept(TokenKindCloseList); cp.IsNone() {
|
|
|
+ if cp := parser.Accept(TokenKindCloseList); cp.IsNone() || cp.IsError() {
|
|
|
return parser.NewAstError("expected closing brackets")
|
|
|
}
|
|
|
|
|
@@ -165,12 +208,18 @@ func (parser *Parser) ParseList() Ast {
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseParenthesis() Ast {
|
|
|
+func (parser *Parser) ParseParenthesis() *Ast {
|
|
|
+ parser.LogDebug("ParseParenthesis: %s\n", parser.current.String())
|
|
|
+
|
|
|
op := parser.Accept(TokenKindOpenParen)
|
|
|
|
|
|
if op.IsNone() {
|
|
|
return NewAstNone()
|
|
|
}
|
|
|
+ if op.IsError() {
|
|
|
+ return parser.NewAstError("Unexpected value.")
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
ast := NewAstWithToken(AstKindParenthesis, op)
|
|
|
expr := parser.ParseExpression()
|
|
@@ -180,7 +229,7 @@ func (parser *Parser) ParseParenthesis() Ast {
|
|
|
if AstIsError(expr) {
|
|
|
return expr
|
|
|
}
|
|
|
- if cp := parser.Accept(TokenKindCloseParen); cp.IsNone() {
|
|
|
+ if cp := parser.Accept(TokenKindCloseParen); cp.IsNone() || cp.IsError() {
|
|
|
return parser.NewAstError("expected closing parenthesis")
|
|
|
}
|
|
|
|
|
@@ -188,11 +237,16 @@ func (parser *Parser) ParseParenthesis() Ast {
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseBlock() Ast {
|
|
|
+func (parser *Parser) ParseBlock() *Ast {
|
|
|
+ parser.LogDebug("ParseBlock: %s\n", parser.current.String())
|
|
|
+
|
|
|
op := parser.Accept(TokenKindOpenBlock)
|
|
|
if op.IsNone() {
|
|
|
return NewAstNone()
|
|
|
}
|
|
|
+ if op.IsError() {
|
|
|
+ return parser.NewAstError("Unexpected value.")
|
|
|
+ }
|
|
|
|
|
|
ast := NewAstWithToken(AstKindBlock, op)
|
|
|
stats := parser.ParseStatements()
|
|
@@ -202,7 +256,7 @@ func (parser *Parser) ParseBlock() Ast {
|
|
|
if AstIsError(stats) {
|
|
|
return stats
|
|
|
}
|
|
|
- if cp := parser.Accept(TokenKindCloseBlock); cp.IsNone() {
|
|
|
+ if cp := parser.Accept(TokenKindCloseBlock); cp.IsNone() || cp.IsError() {
|
|
|
return parser.NewAstError("expected closing block")
|
|
|
}
|
|
|
|
|
@@ -211,7 +265,9 @@ func (parser *Parser) ParseBlock() Ast {
|
|
|
}
|
|
|
|
|
|
/* Parses the target of a set or get expression */
|
|
|
-func (parser *Parser) ParseTarget() Ast {
|
|
|
+func (parser *Parser) ParseTarget() *Ast {
|
|
|
+ parser.LogDebug("ParseTarget: %s\n", parser.current.String())
|
|
|
+
|
|
|
target := parser.Accept(TokenKindWord, TokenKindType, TokenKindSymbol)
|
|
|
ast := NewAstWithToken(AstKindTarget, target)
|
|
|
|
|
@@ -226,7 +282,9 @@ func (parser *Parser) ParseTarget() Ast {
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseSet() Ast {
|
|
|
+func (parser *Parser) ParseSet() *Ast {
|
|
|
+ parser.LogDebug("ParseSet: %s\n", parser.current.String())
|
|
|
+
|
|
|
set := parser.Accept(TokenKindSet)
|
|
|
if set.IsNone() {
|
|
|
return NewAstNone()
|
|
@@ -244,8 +302,10 @@ func (parser *Parser) ParseSet() Ast {
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseGet() Ast {
|
|
|
- get := parser.Accept(TokenKindGet)
|
|
|
+func (parser *Parser) ParseGet() *Ast {
|
|
|
+ parser.LogDebug("ParseGet: %s\n", parser.current.String())
|
|
|
+
|
|
|
+ get := parser.Accept(TokenKindGet)
|
|
|
if get.IsNone() {
|
|
|
return NewAstNone()
|
|
|
}
|
|
@@ -255,7 +315,9 @@ func (parser *Parser) ParseGet() Ast {
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseCommand() Ast {
|
|
|
+func (parser *Parser) ParseCommand() *Ast {
|
|
|
+ parser.LogDebug("ParseCommand: %s\n", parser.current.String())
|
|
|
+
|
|
|
word := parser.Accept(TokenKindWord, TokenKindType)
|
|
|
if word.IsNone() {
|
|
|
return NewAstNone()
|
|
@@ -266,48 +328,75 @@ func (parser *Parser) ParseCommand() Ast {
|
|
|
return command
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseExpression() Ast {
|
|
|
- exp := parser.ParseRequireAny(AstKindExpression, (*Parser).ParseSet,
|
|
|
- (*Parser).ParseGet, (*Parser).ParseCommand, (*Parser).ParseValue )
|
|
|
+func (parser *Parser) ParseClosed() *Ast {
|
|
|
+ parser.LogDebug("ParseClosed: %s\n", parser.current.String())
|
|
|
+ exp := parser.ParseAny(AstKindClosed, (*Parser).ParseParenthesis,
|
|
|
+ (*Parser).ParseBlock, (*Parser).ParseList)
|
|
|
return exp
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseEmptyStatement() Ast {
|
|
|
- eox := parser.Accept(TokenKindEOX)
|
|
|
- if eox.IsNone() {
|
|
|
- return NewAstNone()
|
|
|
+func (parser *Parser) ParseExpression() *Ast {
|
|
|
+ parser.LogDebug("ParseExpression: %s\n", parser.current.String())
|
|
|
+ exp := parser.ParseRequireAny(AstKindExpression, (*Parser).ParseCommand,
|
|
|
+ (*Parser).ParseSet,
|
|
|
+ (*Parser).ParseGet, (*Parser).ParseValue )
|
|
|
+ return exp
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *Parser) ParseExpressionStatement() *Ast {
|
|
|
+ parser.LogDebug("ParseExpressionStatement: %s\n", parser.current.String())
|
|
|
+ expr := parser.ParseExpression()
|
|
|
+ if expr.IsNone() {
|
|
|
+ return NewAstNone()
|
|
|
+ }
|
|
|
+
|
|
|
+ if eox := parser.Accept(TokenKindEOX); eox.IsNone() {
|
|
|
+ return parser.NewAstError("expected end of statement")
|
|
|
}
|
|
|
- ast := NewAstWithToken(AstKindEnd, eox)
|
|
|
- return ast
|
|
|
+
|
|
|
+ return NewAstNone()
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseStatement() Ast {
|
|
|
- ast := parser.ParseRequireAny(AstKindStatement,
|
|
|
- (*Parser).ParseBlock,
|
|
|
- (*Parser).ParseSet,
|
|
|
- (*Parser).ParseGet,
|
|
|
- (*Parser).ParseCommand,
|
|
|
- (*Parser).ParseParenthesis)
|
|
|
+
|
|
|
+func (parser *Parser) ParseEmptyStatement() *Ast {
|
|
|
+ parser.LogDebug("ParseEmptyStatement: %s\n", parser.current.String())
|
|
|
if eox := parser.Accept(TokenKindEOX); eox.IsNone() {
|
|
|
return parser.NewAstError("expected end of statement")
|
|
|
}
|
|
|
+ return NewAstWithToken(AstKindStatement, parser.current)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *Parser) ParseStatement() *Ast {
|
|
|
+ parser.LogDebug("ParseStatement: %s\n", parser.current.String())
|
|
|
+
|
|
|
+ ast := parser.ParseAny(AstKindStatement,
|
|
|
+ (*Parser).ParseClosed,
|
|
|
+ (*Parser).ParseExpressionStatement,
|
|
|
+ (*Parser).ParseEmptyStatement)
|
|
|
return ast
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseStatements() Ast {
|
|
|
- return parser.ParseMany(AstKindStatements, nil, (*Parser).ParseStatement)
|
|
|
+func (parser *Parser) ParseStatements() *Ast {
|
|
|
+ parser.LogDebug("ParseStatements: %s\n", parser.current.String())
|
|
|
+ return parser.ParseMany(AstKindStatements, nil, (*Parser).ParseStatement)
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) ParseProgram() Ast {
|
|
|
- eof := parser.Accept(TokenKindEOF)
|
|
|
- aeof := NewAstWithToken(AstKindEnd, eof)
|
|
|
+func (parser *Parser) ParseProgram() *Ast {
|
|
|
+ parser.LogDebug("ParseProgram: %s\n", parser.current.String())
|
|
|
+
|
|
|
stats := parser.ParseStatements()
|
|
|
// Be lenient with missing EOF for now...
|
|
|
- children := []Ast{stats, aeof}
|
|
|
+ eof := parser.Accept(TokenKindEOF)
|
|
|
+ aeof := NewAstWithToken(AstKindEnd, eof)
|
|
|
+ if eof.IsNone() {
|
|
|
+ aeof = parser.NewAstError("Expceted EOF, have: %s", parser.current.String())
|
|
|
+ }
|
|
|
+ children := []*Ast{stats, aeof}
|
|
|
return NewAst(AstKindProgram, nil, children, NoToken())
|
|
|
}
|
|
|
|
|
|
-func (parser *Parser) Parse() Ast {
|
|
|
+func (parser *Parser) Parse() *Ast {
|
|
|
ast := parser.ParseProgram()
|
|
|
return ast
|
|
|
}
|