diff --git a/evaluator/smalltalkEvaluator.go b/evaluator/smalltalkEvaluator.go index 10b9c1e..0682cd3 100644 --- a/evaluator/smalltalkEvaluator.go +++ b/evaluator/smalltalkEvaluator.go @@ -14,13 +14,13 @@ func NewTestEvaluator() *Evaluator { func TestEval(codeString string) treeNodes.SmalltalkObjectInterface { evaluator := NewTestEvaluator() - programNode := parser.InitializeParserFor(codeString) + programNode, _ := parser.InitializeParserFor(codeString) return evaluator.EvaluateProgram(programNode) } func TestEvalWithScope(codeString string, scope *treeNodes.Scope) treeNodes.SmalltalkObjectInterface { evaluator := NewEvaluatorWithGlobalScope(scope) - programNode := parser.InitializeParserFor(codeString) + programNode, _ := parser.InitializeParserFor(codeString) return evaluator.EvaluateProgram(programNode) } @@ -62,7 +62,11 @@ func (e *Evaluator) GetGlobalScope() *treeNodes.Scope { func (e *Evaluator) RunProgram(programString string) treeNodes.SmalltalkObjectInterface { _, ok := e.programCache[programString] if !ok { - e.programCache[programString] = parser.InitializeParserFor(programString) + initializedParser, err := parser.InitializeParserFor(programString) + if err != nil { + return treeNodes.NewSmalltalkString(err.Error()) + } + e.programCache[programString] = initializedParser } evaluatorProgram := e.programCache[programString] return e.EvaluateProgram(evaluatorProgram) @@ -109,6 +113,9 @@ func (e *Evaluator) EvaluateToBool(programString string) bool { func (e *Evaluator) EvaluateToInterface(programString string) interface{} { resultObject := e.RunProgram(programString) + if resultObject == nil { + return nil + } switch resultObject.TypeOf() { case treeNodes.NUMBER_OBJ: return resultObject.(*treeNodes.SmalltalkNumber).GetValue() @@ -117,7 +124,11 @@ func (e *Evaluator) EvaluateToInterface(programString string) interface{} { case treeNodes.BOOLEAN_OBJ: return resultObject.(*treeNodes.SmalltalkBoolean).GetValue() case treeNodes.ARRAY_OBJ: - return resultObject.(*treeNodes.SmalltalkArray).GetValue() + array, err := resultObject.(*treeNodes.SmalltalkArray).GetValue() + if err != nil { + return nil + } + return array default: return nil } diff --git a/parser/smalltalkParser.go b/parser/smalltalkParser.go index 4cfea43..a65c459 100644 --- a/parser/smalltalkParser.go +++ b/parser/smalltalkParser.go @@ -1,6 +1,7 @@ package parser import ( + "errors" "strconv" "strings" @@ -16,37 +17,40 @@ type Parser struct { emptyStatements bool } -func InitializeParserFor(expressionString string) treeNodes.ProgramNodeInterface { +func InitializeParserFor(expressionString string) (treeNodes.ProgramNodeInterface, error) { reader := talkio.NewReader(expressionString) scanner := scanner.New(*reader) parser := &Parser{scanner, nil, nil, false} //initialize struct members parser.step() - node := parser.parseExpression() + node, err := parser.parseExpression() + if err != nil { + return nil, err + } if len(node.GetStatements()) == 1 && len(node.GetTemporaries()) == 0 { - return node.GetStatements()[0] + return node.GetStatements()[0], nil } else { - return node + return node, nil } } -func (p *Parser) parseExpression() *treeNodes.SequenceNode { - node := p.parseStatements(false) - return node +func (p *Parser) parseExpression() (*treeNodes.SequenceNode, error) { + return p.parseStatements(false) } -func (p *Parser) parseStatements(tagBool bool) *treeNodes.SequenceNode { +func (p *Parser) parseStatements(tagBool bool) (*treeNodes.SequenceNode, error) { var leftBar int64 var rightBar int64 var args []*treeNodes.VariableNode + var err error if p.currentToken.IsBinary() { if p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "|" { leftBar = p.currentToken.GetStart() p.step() - args = p.parseArgs() - if !(p.currentToken.IsBinary() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "|") { - panic("Parse error in parseStatements function.") + args, err = p.parseArgs() + if err != nil || !(p.currentToken.IsBinary() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "|") { + return nil, errors.New("Parse error in parseStatements function.") } rightBar = p.currentToken.GetStart() p.step() @@ -62,26 +66,34 @@ func (p *Parser) parseStatements(tagBool bool) *treeNodes.SequenceNode { node.SetLeftBar(leftBar) node.SetRightBar(rightBar) node.SetTemporaries(args) - return p.parseStatementListInto(tagBool, node) + parsedStatementList, err := p.parseStatementListInto(tagBool, node) + if err != nil { + return nil, err + } + return parsedStatementList, nil } -func (p *Parser) parseArgs() []*treeNodes.VariableNode { +func (p *Parser) parseArgs() ([]*treeNodes.VariableNode, error) { var args []*treeNodes.VariableNode for p.currentToken.IsIdentifier() { - args = append(args, p.parseVariableNode()) + parsedVar, err := p.parseVariableNode() + if err != nil { + return nil, err + } + args = append(args, parsedVar) } - return args + return args, nil } -func (p *Parser) parseVariableNode() *treeNodes.VariableNode { +func (p *Parser) parseVariableNode() (*treeNodes.VariableNode, error) { if p.currentToken.IsIdentifier() { - return p.parsePrimitiveIdentifier() + return p.parsePrimitiveIdentifier(), nil } else { - panic("we expect variable name here btw") + return nil, errors.New("we expect variable name here btw") } } -func (p *Parser) parseStatementListInto(tagBool bool, sequenceNode *treeNodes.SequenceNode) *treeNodes.SequenceNode { +func (p *Parser) parseStatementListInto(tagBool bool, sequenceNode *treeNodes.SequenceNode) (*treeNodes.SequenceNode, error) { returnFlag := false var periods []int64 var statements []treeNodes.ProgramNodeInterface @@ -90,13 +102,16 @@ func (p *Parser) parseStatementListInto(tagBool bool, sequenceNode *treeNodes.Se } for !(p.atEnd() || (p.currentToken.IsSpecial() && IncludesInString("])}", p.currentToken.(scanner.ValueTokenInterface).ValueOfToken()))) { if returnFlag { - panic("End of statement list encountered") + return nil, errors.New("End of statement list encountered") } if p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == `^` { //TODO: smalltalk return statement ^ - panic("we should not have smalltalk return statement eg ^ in our script") + return nil, errors.New("we should not have smalltalk return statement eg ^ in our script") } else { - node := p.parseAssignment() + node, err := p.parseAssignment() + if err != nil { + return nil, err + } statements = append(statements, node) } if p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == `.` { @@ -115,27 +130,38 @@ func (p *Parser) parseStatementListInto(tagBool bool, sequenceNode *treeNodes.Se } sequenceNode.SetStatements(statements) sequenceNode.SetPeriods(periods) - return sequenceNode + return sequenceNode, nil } -func (p *Parser) parseAssignment() treeNodes.ValueNodeInterface { +func (p *Parser) parseAssignment() (treeNodes.ValueNodeInterface, error) { if !(p.currentToken.IsIdentifier() && p.nextToken().IsAssignment()) { return p.parseCascadeMessage() } - node := p.parseVariableNode() + node, err := p.parseVariableNode() + if err != nil { + return nil, err + } position := p.currentToken.GetStart() p.step() assignmentNode := treeNodes.NewAssignmentNode() assignmentNode.SetVariable(node) - assignmentNode.SetValue(p.parseAssignment()) + parsedValue, err := p.parseAssignment() + if err != nil { + return nil, err + } + assignmentNode.SetValue(parsedValue) assignmentNode.SetPosition(position) - return assignmentNode + return assignmentNode, nil } -func (p *Parser) parseCascadeMessage() treeNodes.ValueNodeInterface { - node := p.parseKeywordMessage() +func (p *Parser) parseCascadeMessage() (treeNodes.ValueNodeInterface, error) { + var err error + node, err := p.parseKeywordMessage() + if err != nil { + return nil, err + } if !(p.currentToken.IsSpecial() && (p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == ";" && node.IsMessage())) { - return node + return node, nil } receiver := node.(treeNodes.NodeWithRreceiverInterface).GetReceiver() var messages []*treeNodes.MessageNode @@ -146,17 +172,24 @@ func (p *Parser) parseCascadeMessage() treeNodes.ValueNodeInterface { p.step() var message *treeNodes.MessageNode if p.currentToken.IsIdentifier() { - message = p.parseKeywordMessageWith(receiver).(*treeNodes.MessageNode) + tmpMsg, err := p.parseKeywordMessageWith(receiver) + if err != nil { + return nil, err + } + message = tmpMsg.(*treeNodes.MessageNode) } else { if p.currentToken.IsLiteralToken() { p.patchNegativeLiteral() } if !p.currentToken.IsBinary() { - panic("message expected") + return nil, errors.New("message expected") + } + temp, err := p.parseBinaryMessageWith(receiver) + if err != nil { + return nil, err } - temp := p.parseBinaryMessageWith(receiver) if temp == receiver { - panic("message expected") + return nil, errors.New("message expected") } message = temp } @@ -166,7 +199,7 @@ func (p *Parser) parseCascadeMessage() treeNodes.ValueNodeInterface { cascadeNode := treeNodes.NewCascadeNode() cascadeNode.SetSemicolons(semicolons) cascadeNode.SetMessages(messages) - return cascadeNode + return cascadeNode, nil } func (p *Parser) patchNegativeLiteral() { @@ -191,35 +224,49 @@ func (p *Parser) patchNegativeLiteral() { p.peekToken.SetStart(p.peekToken.GetStart() + 1) } -func (p *Parser) parseKeywordMessage() treeNodes.ValueNodeInterface { - return p.parseKeywordMessageWith(p.parseBinaryMessage()) +func (p *Parser) parseKeywordMessage() (treeNodes.ValueNodeInterface, error) { + parsedBinary, err := p.parseBinaryMessage() + if err != nil { + return nil, err + } + return p.parseKeywordMessageWith(parsedBinary) } -func (p *Parser) parseKeywordMessageWith(valueNode treeNodes.ValueNodeInterface) treeNodes.ValueNodeInterface { +func (p *Parser) parseKeywordMessageWith(valueNode treeNodes.ValueNodeInterface) (treeNodes.ValueNodeInterface, error) { var keywords []scanner.ValueTokenInterface var arguments []treeNodes.ValueNodeInterface isKeyword := false for p.currentToken.IsKeyword() { keywords = append(keywords, p.currentToken.(scanner.ValueTokenInterface)) p.step() - arguments = append(arguments, p.parseBinaryMessage()) + parsedBinary, err := p.parseBinaryMessage() + if err != nil { + return nil, err + } + arguments = append(arguments, parsedBinary) isKeyword = true } if isKeyword { node := treeNodes.NewMessageNode() node.SetReceiverSelectorPartsArguments(valueNode, keywords, arguments) - return node + return node, nil } else { - return valueNode + return valueNode, nil } } -func (p *Parser) parseBinaryMessage() treeNodes.ValueNodeInterface { - node := p.parseUnaryMessage() +func (p *Parser) parseBinaryMessage() (treeNodes.ValueNodeInterface, error) { + node, err := p.parseUnaryMessage() + if err != nil { + return nil, err + } for p.isBinaryAfterPatch() { - node = p.parseBinaryMessageWith(node) + node, err = p.parseBinaryMessageWith(node) + if err != nil { + return nil, err + } } - return node + return node, nil } func (p *Parser) isBinaryAfterPatch() bool { @@ -229,23 +276,31 @@ func (p *Parser) isBinaryAfterPatch() bool { return p.currentToken.IsBinary() } -func (p *Parser) parseBinaryMessageWith(nodeInterface treeNodes.ValueNodeInterface) *treeNodes.MessageNode { +func (p *Parser) parseBinaryMessageWith(nodeInterface treeNodes.ValueNodeInterface) (*treeNodes.MessageNode, error) { selector := p.currentToken.(*scanner.BinarySelectorToken) p.step() node := treeNodes.NewMessageNode() - selectorParts := []scanner.ValueTokenInterface{selector} //literal array with one selector - arguments := []treeNodes.ValueNodeInterface{p.parseUnaryMessage()} + selectorParts := []scanner.ValueTokenInterface{selector} + parsedUnary, err := p.parseUnaryMessage() + if err != nil { + return nil, err + } + //literal array with one selector + arguments := []treeNodes.ValueNodeInterface{parsedUnary} node.SetReceiverSelectorPartsArguments(nodeInterface, selectorParts, arguments) - return node + return node, nil } -func (p *Parser) parseUnaryMessage() treeNodes.ValueNodeInterface { - node := p.parsePrimitiveObject() +func (p *Parser) parseUnaryMessage() (treeNodes.ValueNodeInterface, error) { + node, err := p.parsePrimitiveObject() + if err != nil { + return nil, err + } for p.currentToken.IsIdentifier() { //TODO: patchLiteralMessage node = p.parseUnaryMessageWith(node) } - return node + return node, nil } func (p *Parser) parseUnaryMessageWith(nodeInterface treeNodes.ValueNodeInterface) *treeNodes.MessageNode { @@ -258,12 +313,12 @@ func (p *Parser) parseUnaryMessageWith(nodeInterface treeNodes.ValueNodeInterfac return node } -func (p *Parser) parsePrimitiveObject() treeNodes.ValueNodeInterface { +func (p *Parser) parsePrimitiveObject() (treeNodes.ValueNodeInterface, error) { if p.currentToken.IsIdentifier() { - return p.parsePrimitiveIdentifier() + return p.parsePrimitiveIdentifier(), nil } if p.currentToken.IsLiteralToken() && !(p.currentToken.(scanner.LiteralTokenInterface).IsMultiKeyword()) { - return p.parsePrimitiveLiteral() + return p.parsePrimitiveLiteral(), nil } if p.currentToken.IsLiteralArrayToken() { //TODO: ByteArray @@ -278,26 +333,30 @@ func (p *Parser) parsePrimitiveObject() treeNodes.ValueNodeInterface { } } //in case of emergency LUL - panic("what is our token?") + return nil, errors.New("what is our token?") } -func (p *Parser) parseBlock() *treeNodes.BlockNode { +func (p *Parser) parseBlock() (*treeNodes.BlockNode, error) { position := p.currentToken.GetStart() p.step() node := treeNodes.NewBlockNode() p.parseBlockArgsInto(node) node.SetLeft(position) - node.SetBody(p.parseStatements(false)) + parsedStatements, err := p.parseStatements(false) + if err != nil { + return nil, err + } + node.SetBody(parsedStatements) if !(p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "]") { - panic("Close bracket expected smth like ]") + return nil, errors.New("Close bracket expected smth like ]") } node.SetRight(p.currentToken.GetStart()) p.step() - return node + return node, nil } -func (p *Parser) parseBlockArgsInto(node *treeNodes.BlockNode) *treeNodes.BlockNode { +func (p *Parser) parseBlockArgsInto(node *treeNodes.BlockNode) (*treeNodes.BlockNode, error) { var args []*treeNodes.VariableNode var colons []int64 verticalBar := false @@ -305,7 +364,11 @@ func (p *Parser) parseBlockArgsInto(node *treeNodes.BlockNode) *treeNodes.BlockN colons = append(colons, p.currentToken.GetStart()) p.step() verticalBar = true - args = append(args, p.parseVariableNode()) + parsedVariable, err := p.parseVariableNode() + if err != nil { + return nil, err + } + args = append(args, parsedVariable) } if verticalBar { if p.currentToken.IsBinary() { @@ -313,52 +376,59 @@ func (p *Parser) parseBlockArgsInto(node *treeNodes.BlockNode) *treeNodes.BlockN if p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "|" { p.step() } else { - panic("bar inside block node is expected") + return nil, errors.New("bar inside block node is expected") } } else { if !(p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "]") { - panic("bar inside block node is expected") + return nil, errors.New("bar inside block node is expected") } } } node.SetArguments(args) node.SetColons(colons) - return node + return node, nil } -func (p *Parser) parseParenthesizedExpression() treeNodes.ValueNodeInterface { +func (p *Parser) parseParenthesizedExpression() (treeNodes.ValueNodeInterface, error) { leftParen := p.currentToken.GetStart() p.step() - node := p.parseAssignment() + node, err := p.parseAssignment() + if err != nil { + return nil, err + } if p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == ")" { interval := treeNodes.Interval{} interval.SetStart(p.currentToken.GetStart()) interval.SetStop(leftParen) node.AddParenthesis(interval) p.step() - return node + return node, nil } else { - panic("close parenthesis expected. something like ) ") + return nil, errors.New("close parenthesis expected. something like ) ") } } -func (p *Parser) parseLiteralArray() treeNodes.LiteralNodeInterface { +func (p *Parser) parseLiteralArray() (treeNodes.LiteralNodeInterface, error) { var contents []treeNodes.LiteralNodeInterface start := p.currentToken.GetStart() p.step() for !(p.atEnd() || (p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == ")")) { - contents = append(contents, p.parseLiteralArrayObject()) + parsedLiteralArray, err := p.parseLiteralArrayObject() + if err != nil { + return nil, err + } + contents = append(contents, parsedLiteralArray) } if !(p.currentToken.IsSpecial() && p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == ")") { - panic("hmm parse error btw. we expect ) here") + return nil, errors.New("hmm parse error btw. we expect ) here") } stop := p.currentToken.(scanner.ValueTokenInterface).GetStop() p.step() node := treeNodes.CreateLiteralArrayNode(start, stop, contents) - return node + return node, nil } -func (p *Parser) parseLiteralArrayObject() treeNodes.LiteralNodeInterface { +func (p *Parser) parseLiteralArrayObject() (treeNodes.LiteralNodeInterface, error) { if p.currentToken.IsSpecial() { if p.currentToken.(scanner.ValueTokenInterface).ValueOfToken() == "(" { return p.parseLiteralArray() @@ -371,14 +441,14 @@ func (p *Parser) parseLiteralArrayObject() treeNodes.LiteralNodeInterface { if p.currentToken.IsLiteralArrayToken() { if p.currentToken.IsForByteArray() { //TODO: ByteArray - return nil + return nil, errors.New("Not implemented") } else { return p.parseLiteralArray() } } //TODO: Optimized token //TODO: patchLiteralArrayToken - return p.parsePrimitiveLiteral() + return p.parsePrimitiveLiteral(), nil } func (p *Parser) parsePrimitiveIdentifier() *treeNodes.VariableNode { @@ -397,18 +467,24 @@ func (p *Parser) parsePrimitiveLiteral() treeNodes.LiteralNodeInterface { return node } -func (p *Parser) step() { +func (p *Parser) step() error { if p.peekToken != nil { p.currentToken = p.peekToken p.peekToken = nil } else { - p.currentToken = p.scanner.Next() + currentToken, err := p.scanner.Next() + if err != nil { + return err + } + p.currentToken = currentToken } + return nil } func (p *Parser) nextToken() scanner.TokenInterface { if p.peekToken == nil { - p.peekToken = p.scanner.Next() + peekToken, _ := p.scanner.Next() + p.peekToken = peekToken } return p.peekToken } diff --git a/parser/smalltalkParser_test.go b/parser/smalltalkParser_test.go index 1fe761c..684f0ec 100644 --- a/parser/smalltalkParser_test.go +++ b/parser/smalltalkParser_test.go @@ -10,178 +10,178 @@ import ( func TestNumberParser(t *testing.T) { inputString := `5.1` - literalNode := InitializeParserFor(inputString).(*treeNodes.LiteralValueNode) - testutils.ASSERT_STREQ(t, literalNode.GetValue(), "5.1") + literalNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, literalNode.(*treeNodes.LiteralValueNode).GetValue(), "5.1") } func TestStringParser(t *testing.T) { inputString := `'test'` - identifierNode := InitializeParserFor(inputString).(*treeNodes.LiteralValueNode) - testutils.ASSERT_STREQ(t, identifierNode.GetValue(), "test") + identifierNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, identifierNode.(*treeNodes.LiteralValueNode).GetValue(), "test") } func TestBoolParser(t *testing.T) { inputString := `false` - identifierNode := InitializeParserFor(inputString).(*treeNodes.LiteralValueNode) - testutils.ASSERT_STREQ(t, identifierNode.GetValue(), "false") + identifierNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, identifierNode.(*treeNodes.LiteralValueNode).GetValue(), "false") } func TestAssignmentNumberParser(t *testing.T) { inputString := `a := 5` - assignmentNode := InitializeParserFor(inputString).(*treeNodes.AssignmentNode) - testutils.ASSERT_STREQ(t, assignmentNode.GetVariable().Token.ValueOfToken(), "a") - testutils.ASSERT_TRUE(t, assignmentNode.GetValue().IsLiteralNode()) - testutils.ASSERT_STREQ(t, assignmentNode.GetValue().(*treeNodes.LiteralValueNode).GetValue(), "5") + assignmentNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") + testutils.ASSERT_TRUE(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().IsLiteralNode()) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralValueNode).GetValue(), "5") } func TestAssignmentStringParser(t *testing.T) { inputString := `a := 'b'` - assignmentNode := InitializeParserFor(inputString).(*treeNodes.AssignmentNode) - testutils.ASSERT_STREQ(t, assignmentNode.GetVariable().Token.ValueOfToken(), "a") - testutils.ASSERT_TRUE(t, assignmentNode.GetValue().IsLiteralNode()) - testutils.ASSERT_STREQ(t, assignmentNode.GetValue().(*treeNodes.LiteralValueNode).GetValue(), "b") + assignmentNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") + testutils.ASSERT_TRUE(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().IsLiteralNode()) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralValueNode).GetValue(), "b") } func TestAssignmentBoolParser(t *testing.T) { inputString := `a := true` - assignmentNode := InitializeParserFor(inputString).(*treeNodes.AssignmentNode) - testutils.ASSERT_STREQ(t, assignmentNode.GetVariable().Token.ValueOfToken(), "a") - testutils.ASSERT_TRUE(t, assignmentNode.GetValue().IsLiteralNode()) - testutils.ASSERT_STREQ(t, assignmentNode.GetValue().(*treeNodes.LiteralValueNode).GetValue(), "true") + assignmentNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") + testutils.ASSERT_TRUE(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().IsLiteralNode()) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralValueNode).GetValue(), "true") } func TestAssignmentLiteralArrayParser(t *testing.T) { inputString := `a := #(1 2)` - assignmentNode := InitializeParserFor(inputString).(*treeNodes.AssignmentNode) - testutils.ASSERT_STREQ(t, assignmentNode.GetVariable().Token.ValueOfToken(), "a") - testutils.ASSERT_TRUE(t, assignmentNode.GetValue().IsLiteralArray()) - testutils.ASSERT_STREQ(t, assignmentNode.GetValue().(*treeNodes.LiteralArrayNode).GetValue(), "1 2") + assignmentNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") + testutils.ASSERT_TRUE(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().IsLiteralArray()) + testutils.ASSERT_STREQ(t, assignmentNode.(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralArrayNode).GetValue(), "1 2") } func TestBinaryMessageParser(t *testing.T) { inputString := `a + b` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.VariableNode).GetName(), "a") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.VariableNode).GetName(), "b") + messageNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "b") } func TestNumberWithMinusParser(t *testing.T) { inputString := `2*3-4` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) + messageNode, _ := InitializeParserFor(inputString) testutils.ASSERT_TRUE(t, messageNode.IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.LiteralValueNode).GetValue(), "2") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "*") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "3") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "4.00") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.LiteralValueNode).GetValue(), "2") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "*") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "3") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "4.00") } func TestFewBinaryMessageParser(t *testing.T) { inputString := `a - b + c` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) + messageNode, _ := InitializeParserFor(inputString) testutils.ASSERT_TRUE(t, messageNode.IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "b") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.VariableNode).GetName(), "c") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "b") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "c") } func TestGroupMessageParser(t *testing.T) { inputString := `a - (b + c)` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) + messageNode, _ := InitializeParserFor(inputString) testutils.ASSERT_TRUE(t, messageNode.IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.VariableNode).GetName(), "a") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 1) - testutils.ASSERT_TRUE(t, messageNode.GetArguments()[0].IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "b") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()[0].(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()[0].(*treeNodes.MessageNode).GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "c") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "-") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_TRUE(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].IsMessage()) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "b") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.VariableNode).GetName(), "c") } func TestUnaryMessageParser(t *testing.T) { inputString := `-1 abs` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.LiteralValueNode).GetValue(), "-1") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].(*scanner.IdentifierToken).ValueOfToken(), "abs") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 0) + messageNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.LiteralValueNode).GetValue(), "-1") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.IdentifierToken).ValueOfToken(), "abs") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 0) } func TestIfStatementParser(t *testing.T) { inputString := `a > 10 ifTrue:[25] ifFalse:[2]` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) - testutils.ASSERT_TRUE(t, messageNode.GetReceiver().IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), ">") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "10") - testutils.ASSERT_STREQ(t, messageNode.GetSelector(), "ifTrue:ifFalse:") - testutils.ASSERT_TRUE(t, len(messageNode.GetSelectorParts()) == 2) - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[0].ValueOfToken(), "ifTrue:") - testutils.ASSERT_STREQ(t, messageNode.GetSelectorParts()[1].ValueOfToken(), "ifFalse:") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()) == 2) - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "25") - testutils.ASSERT_TRUE(t, len(messageNode.GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "2") + messageNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_TRUE(t, messageNode.(*treeNodes.MessageNode).GetReceiver().IsMessage()) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), ">") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "10") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelector(), "ifTrue:ifFalse:") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetSelectorParts()) == 2) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[0].ValueOfToken(), "ifTrue:") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetSelectorParts()[1].ValueOfToken(), "ifFalse:") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()) == 2) + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "25") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "2") } func TestIfStatementWithExpressionParser(t *testing.T) { inputString := `(pitch>0.9 ifTrue:[1] ifFalse:[0])*23` - messageNode := InitializeParserFor(inputString).(*treeNodes.MessageNode) - testutils.ASSERT_TRUE(t, messageNode.GetReceiver().IsMessage()) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "pitch") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), ">") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "0.9") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 2) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].ValueOfToken(), "ifTrue:") - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[1].ValueOfToken(), "ifFalse:") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 2) - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "1") - testutils.ASSERT_TRUE(t, len(messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) - testutils.ASSERT_STREQ(t, messageNode.GetReceiver().(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "0") - testutils.ASSERT_STREQ(t, messageNode.GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "23") + messageNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_TRUE(t, messageNode.(*treeNodes.MessageNode).GetReceiver().IsMessage()) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "pitch") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), ">") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "0.9") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()) == 2) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[0].ValueOfToken(), "ifTrue:") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetSelectorParts()[1].ValueOfToken(), "ifFalse:") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()) == 2) + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "1") + testutils.ASSERT_TRUE(t, len(messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()) == 1) + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetReceiver().(*treeNodes.MessageNode).GetArguments()[1].(*treeNodes.BlockNode).GetBody().GetStatements()[0].(*treeNodes.LiteralValueNode).GetValue(), "0") + testutils.ASSERT_STREQ(t, messageNode.(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "23") } func TestSequenceParser(t *testing.T) { inputString := `a := 2. a + 2` - sequenceNode := InitializeParserFor(inputString).(*treeNodes.SequenceNode) - testutils.ASSERT_TRUE(t, len(sequenceNode.GetStatements()) == 2) - testutils.ASSERT_TRUE(t, sequenceNode.GetStatements()[0].IsAssignment()) - testutils.ASSERT_STREQ(t, sequenceNode.GetStatements()[0].(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") - testutils.ASSERT_TRUE(t, sequenceNode.GetStatements()[0].(*treeNodes.AssignmentNode).GetValue().IsLiteralNode()) - testutils.ASSERT_STREQ(t, sequenceNode.GetStatements()[0].(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralValueNode).GetValue(), "2") - testutils.ASSERT_TRUE(t, sequenceNode.GetStatements()[1].IsMessage()) - testutils.ASSERT_STREQ(t, sequenceNode.GetStatements()[1].(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") - testutils.ASSERT_TRUE(t, len(sequenceNode.GetStatements()[1].(*treeNodes.MessageNode).GetSelectorParts()) == 1) - testutils.ASSERT_STREQ(t, sequenceNode.GetStatements()[1].(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") - testutils.ASSERT_TRUE(t, len(sequenceNode.GetStatements()[1].(*treeNodes.MessageNode).GetArguments()) == 1) - testutils.ASSERT_STREQ(t, sequenceNode.GetStatements()[1].(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "2") + sequenceNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_TRUE(t, len(sequenceNode.(*treeNodes.SequenceNode).GetStatements()) == 2) + testutils.ASSERT_TRUE(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[0].IsAssignment()) + testutils.ASSERT_STREQ(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[0].(*treeNodes.AssignmentNode).GetVariable().Token.ValueOfToken(), "a") + testutils.ASSERT_TRUE(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[0].(*treeNodes.AssignmentNode).GetValue().IsLiteralNode()) + testutils.ASSERT_STREQ(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[0].(*treeNodes.AssignmentNode).GetValue().(*treeNodes.LiteralValueNode).GetValue(), "2") + testutils.ASSERT_TRUE(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].IsMessage()) + testutils.ASSERT_STREQ(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].(*treeNodes.MessageNode).GetReceiver().(*treeNodes.VariableNode).GetName(), "a") + testutils.ASSERT_TRUE(t, len(sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].(*treeNodes.MessageNode).GetSelectorParts()) == 1) + testutils.ASSERT_STREQ(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].(*treeNodes.MessageNode).GetSelectorParts()[0].(*scanner.BinarySelectorToken).ValueOfToken(), "+") + testutils.ASSERT_TRUE(t, len(sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].(*treeNodes.MessageNode).GetArguments()) == 1) + testutils.ASSERT_STREQ(t, sequenceNode.(*treeNodes.SequenceNode).GetStatements()[1].(*treeNodes.MessageNode).GetArguments()[0].(*treeNodes.LiteralValueNode).GetValue(), "2") } func TestIdentifierParser(t *testing.T) { inputString := `radio_altitude` - variableNode := InitializeParserFor(inputString).(*treeNodes.VariableNode) - testutils.ASSERT_STREQ(t, variableNode.GetName(), "radio_altitude") + variableNode, _ := InitializeParserFor(inputString) + testutils.ASSERT_STREQ(t, variableNode.(*treeNodes.VariableNode).GetName(), "radio_altitude") } diff --git a/scanner/smalltalkScanner.go b/scanner/smalltalkScanner.go index bb4448c..8d31c6c 100644 --- a/scanner/smalltalkScanner.go +++ b/scanner/smalltalkScanner.go @@ -1,11 +1,13 @@ package scanner import ( - "github.com/SealNTibbers/GotalkInterpreter/talkio" + "errors" "math" "strconv" "strings" "unicode" + + "github.com/SealNTibbers/GotalkInterpreter/talkio" ) const ( @@ -146,16 +148,20 @@ func (s *Scanner) classify(character rune) string { return s.getClassificationTable()[character] } -func (s *Scanner) Next() TokenInterface { +func (s *Scanner) Next() (TokenInterface, error) { s.buffer.Reset() s.tokenStart = s.stream.GetPosition() if s.characterType == EOF { s.token = &EOFToken{&Token{s.tokenStart + 1}} } else { - s.token = s.scanToken() + sT, err := s.scanToken() + if err != nil { + return nil, err + } + s.token = sT } s.stripSeparators() - return s.token + return s.token, nil } func (s *Scanner) previousStepPosition() int64 { @@ -166,9 +172,9 @@ func (s *Scanner) previousStepPosition() int64 { } } -func (s *Scanner) scanToken() TokenInterface { +func (s *Scanner) scanToken() (TokenInterface, error) { if s.characterType == ALPHABET { - return s.scanIdentifierOrKeyword() + return s.scanIdentifierOrKeyword(), nil } if s.characterType == DIGIT || (s.currentCharacter == '-' && s.classify(s.stream.PeekRune()) == DIGIT) { @@ -176,22 +182,22 @@ func (s *Scanner) scanToken() TokenInterface { } if s.characterType == BIN { - return s.scanBinaryInSelector() + return s.scanBinaryInSelector(), nil } if s.characterType == SPEC { - return s.scanSpecialCharacter() + return s.scanSpecialCharacter(), nil } if s.currentCharacter == '\'' { - return s.scanStringSymbol() + return s.scanStringSymbol(), nil } if s.currentCharacter == '#' { - return s.scanLiteral() + return s.scanLiteral(), nil } - return &Token{} + return &Token{}, nil } func (s *Scanner) scanIdentifierOrKeyword() TokenInterface { @@ -256,11 +262,13 @@ func (s *Scanner) scanName() { } } -func (s *Scanner) scanNumber() *NumberLiteralToken { +func (s *Scanner) scanNumber() (*NumberLiteralToken, error) { start := s.stream.GetPosition() - number := s.scanNumberVisualWorks() - + number, err := s.scanNumberVisualWorks() + if err != nil { + return nil, err + } currentPosition := s.stream.GetPosition() var stop int64 @@ -271,58 +279,67 @@ func (s *Scanner) scanNumber() *NumberLiteralToken { } s.stream.SetPosition(start - 1) - _, err := s.stream.ReadRunes(stop - start + 1) + _, err = s.stream.ReadRunes(stop - start + 1) if err != nil { - panic("can't read an amount of runes to scan number") + return nil, errors.New("can't read an amount of runes to scan number") } s.stream.SetPosition(currentPosition) - return &NumberLiteralToken{NewLiteralToken(start, stop, string(number), NUMBER)} + return &NumberLiteralToken{NewLiteralToken(start, stop, string(number), NUMBER)}, nil } -func (s *Scanner) scanNumberVisualWorks() string { +func (s *Scanner) scanNumberVisualWorks() (string, error) { s.stream.Skip(-1) - number := s.readSmalltalkSyntaxFromStream() + number, err := s.readSmalltalkSyntaxFromStream() + if err != nil { + return "", err + } s.step() - return number + return number, nil } -func (s *Scanner) readSmalltalkSyntaxFromStream() string { +func (s *Scanner) readSmalltalkSyntaxFromStream() (string, error) { if s.stream.AtEnd() || unicode.IsLetter(s.stream.PeekRune()) { - return "0" + return "0", nil } neg := s.stream.PeekRuneFor('-') - value := s.readIntegerWithRadix(10) - floatValue := s.readSmalltalkFloat(value) + value, err := s.readIntegerWithRadix(10) + if err != nil { + return "", err + } + floatValue, err := s.readSmalltalkFloat(value) + if err != nil { + return "", err + } if neg { floatValue *= -1 } - return strconv.FormatFloat(floatValue, 'f', -1, 64) + return strconv.FormatFloat(floatValue, 'f', -1, 64), nil } -func (s *Scanner) readIntegerWithRadix(radix int) int { +func (s *Scanner) readIntegerWithRadix(radix int) (int, error) { value := 0 for { if s.stream.AtEnd() { - return value + return value, nil } character, _, err := s.stream.ReadRune() if err != nil { - panic("readIntegerWithRadix doesn't work as expected. FeelsBadMan") + return 0, errors.New("readIntegerWithRadix doesn't work as expected. FeelsBadMan") } digit := CharToNum(character) if digit < 0 || digit >= radix { s.stream.Skip(-1) - return value + return value, nil } else { value = value*radix + digit } } - return value + return value, nil } -func (s *Scanner) readSmalltalkFloat(integerPart int) float64 { +func (s *Scanner) readSmalltalkFloat(integerPart int) (float64, error) { var num, den float64 var atEnd bool var possibleCoercionClass rune @@ -341,7 +358,7 @@ func (s *Scanner) readSmalltalkFloat(integerPart int) float64 { } digit, _, err := s.stream.ReadRune() if err != nil { - panic(err) + return 0.0, err } if !(unicode.IsDigit(digit)) { break @@ -375,7 +392,10 @@ func (s *Scanner) readSmalltalkFloat(integerPart int) float64 { } digit, err := s.stream.PeekRuneError() if err == nil && (digit != 0) && unicode.IsDigit(digit) { - exp = s.readIntegerWithRadix(10) + exp, err = s.readIntegerWithRadix(10) + if err != nil { + return 0, err + } if neg { exp = -1 * exp } @@ -387,9 +407,9 @@ func (s *Scanner) readSmalltalkFloat(integerPart int) float64 { value := float64(integerPart) + (num / den) if exp == 0 { - return value + return value, nil } else { - return value * math.Pow(10, float64(exp)) + return value * math.Pow(10, float64(exp)), nil } } @@ -467,7 +487,6 @@ func (s *Scanner) scanLiteral() TokenInterface { if s.currentCharacter == '(' || s.currentCharacter == '[' { return s.scanLiteralArrayToken() } - panic("Man you have a big problem!!!") return nil } diff --git a/scanner/smalltalkScanner_test.go b/scanner/smalltalkScanner_test.go index 1cc85d7..9afaefa 100644 --- a/scanner/smalltalkScanner_test.go +++ b/scanner/smalltalkScanner_test.go @@ -12,11 +12,11 @@ func TestScanNumber(t *testing.T) { vwReader := talkio.NewReader(inputString) vwScanner := New(*vwReader) var token TokenInterface - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, NUMBER, token.TypeOfToken()) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), "0.56") - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -25,11 +25,11 @@ func TestScanIdentifier(t *testing.T) { vwReader := talkio.NewReader(inputString) vwScanner := New(*vwReader) var token TokenInterface - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, IDENT, token.TypeOfToken()) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), "radio_altitude") - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -38,11 +38,11 @@ func TestScanFloatNumberWithD(t *testing.T) { vwReader := talkio.NewReader(inputString) vwScanner := New(*vwReader) var token TokenInterface - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, NUMBER, token.TypeOfToken()) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), "1.02") - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, "EOFToken", eofToken.TypeOfToken()) } @@ -51,11 +51,11 @@ func TestScanFloatNumberWithExp(t *testing.T) { vwReader := talkio.NewReader(inputString) vwScanner := New(*vwReader) var token TokenInterface - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, NUMBER, token.TypeOfToken()) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), "10000") - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, "EOFToken", eofToken.TypeOfToken()) } @@ -64,11 +64,11 @@ func TestScanFloatNumberWithNegativeExp(t *testing.T) { vwReader := talkio.NewReader(inputString) vwScanner := New(*vwReader) var token TokenInterface - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, NUMBER, token.TypeOfToken()) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), "0.0001") - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -92,11 +92,11 @@ func TestScanRealExpressions(t *testing.T) { vwScanner := New(*vwReader) var token TokenInterface for _, eachTest := range tests { - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, token.TypeOfToken(), eachTest.expectedTokenType) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), eachTest.expectedValue) } - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -127,11 +127,11 @@ func TestScanIfStatementExpressionWithDifferentSubexpressions(t *testing.T) { vwScanner := New(*vwReader) var token TokenInterface for _, eachTest := range tests { - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, token.TypeOfToken(), eachTest.expectedTokenType) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), eachTest.expectedValue) } - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -151,7 +151,7 @@ func TestScanAssignmentExpression(t *testing.T) { foundAssignment := false var index int for i := 0; i < len(tests)+1; i++ { - token = vwScanner.Next() + token, _ = vwScanner.Next() if foundAssignment { index = i - 1 } else { @@ -167,7 +167,7 @@ func TestScanAssignmentExpression(t *testing.T) { } testutils.ASSERT_TRUE(t, foundAssignment) - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } @@ -186,11 +186,11 @@ func TestScanArray(t *testing.T) { vwScanner := New(*vwReader) var token TokenInterface for _, eachTest := range tests { - token = vwScanner.Next() + token, _ = vwScanner.Next() testutils.ASSERT_STREQ(t, token.TypeOfToken(), eachTest.expectedTokenType) testutils.ASSERT_STREQ(t, token.(ValueTokenInterface).ValueOfToken(), eachTest.expectedValue) } - eofToken := vwScanner.Next() + eofToken, _ := vwScanner.Next() testutils.ASSERT_STREQ(t, eofToken.TypeOfToken(), "EOFToken") } diff --git a/talkio/stringReader.go b/talkio/stringReader.go index 9e6c18e..9587063 100644 --- a/talkio/stringReader.go +++ b/talkio/stringReader.go @@ -179,7 +179,7 @@ func (r *StringReader) WriteTo(w io.Writer) (n int64, err error) { s := r.s[r.i:] m, err := io.WriteString(w, s) if m > len(s) { - panic("strings.StringReader.WriteTo: invalid WriteString count") + return 0, errors.New("strings.StringReader.WriteTo: invalid WriteString count") } r.i += int64(m) n = int64(m) diff --git a/treeNodes/nodesEvaluation.go b/treeNodes/nodesEvaluation.go index 3505afe..bc69698 100644 --- a/treeNodes/nodesEvaluation.go +++ b/treeNodes/nodesEvaluation.go @@ -1,7 +1,7 @@ package treeNodes import ( - "fmt" + "errors" "strconv" "github.com/SealNTibbers/GotalkInterpreter/scanner" @@ -42,33 +42,36 @@ func (s *Scope) FindValueByName(name string) (SmalltalkObjectInterface, bool) { return value, ok } -func (s *Scope) GetVarValue(name string) SmalltalkObjectInterface { +func (s *Scope) GetVarValue(name string) (SmalltalkObjectInterface, error) { value, ok := s.variables[name] if ok { - return value + return value, nil } else { if s.OuterScope != nil { return s.OuterScope.GetVarValue(name) } else { - panic(`we do not have variable with "` + name + `" in this scope`) + return nil, errors.New("variable not found") } } } func (message *MessageNode) Eval(scope *Scope) SmalltalkObjectInterface { receiver := message.receiver.Eval(scope) + if receiver == nil { + return NewSmalltalkString("Internal error") + } var argObjects []SmalltalkObjectInterface for _, each := range message.arguments { argument := each.Eval(scope) if argument == nil { each.Eval(scope) - panic("message argument should not be nil (void)") + return nil } argObjects = append(argObjects, argument) } result, err := receiver.Perform(message.GetSelector(), argObjects) if err != nil { - fmt.Println(err) + return NewSmalltalkString(err.Error()) } return result } @@ -94,8 +97,11 @@ func (assignment *AssignmentNode) Eval(scope *Scope) SmalltalkObjectInterface { func (variable *VariableNode) Eval(scope *Scope) SmalltalkObjectInterface { // return value for variable - smalltalkValue := scope.GetVarValue(variable.GetName()) - if smalltalkValue.TypeOf() == DEFERRED { + smalltalkValue, err := scope.GetVarValue(variable.GetName()) + if err != nil { + return NewSmalltalkString(err.Error()) + } + if smalltalkValue != nil && smalltalkValue.TypeOf() == DEFERRED { return smalltalkValue.Value() } else { return smalltalkValue diff --git a/treeNodes/smalltalkObjects.go b/treeNodes/smalltalkObjects.go index c05053f..8143511 100644 --- a/treeNodes/smalltalkObjects.go +++ b/treeNodes/smalltalkObjects.go @@ -533,7 +533,7 @@ func (a *SmalltalkArray) GetValueAt(index int64) SmalltalkObjectInterface { return a.array[index] } -func (a *SmalltalkArray) GetValue() []interface{} { +func (a *SmalltalkArray) GetValue() ([]interface{}, error) { var interfaceSlice = make([]interface{}, len(a.array)) for i, each := range a.array { switch each.TypeOf() { @@ -544,13 +544,16 @@ func (a *SmalltalkArray) GetValue() []interface{} { case BOOLEAN_OBJ: interfaceSlice[i] = each.(*SmalltalkBoolean).GetValue() case ARRAY_OBJ: - innerArray := each.(*SmalltalkArray).GetValue() + innerArray, err := each.(*SmalltalkArray).GetValue() + if err != nil { + return nil, err + } interfaceSlice[i] = innerArray default: - panic(`we do not support this type "` + each.TypeOf() + `" in array`) + return nil, errors.New(`we do not support this type "` + each.TypeOf() + `" in array`) } } - return interfaceSlice + return interfaceSlice, nil } func (a *SmalltalkArray) Value() SmalltalkObjectInterface {