diff --git a/server/internal/lang/interpreter.go b/server/internal/lang/interpreter.go index f4cc607..0b4be30 100644 --- a/server/internal/lang/interpreter.go +++ b/server/internal/lang/interpreter.go @@ -150,6 +150,14 @@ func (i *Interpreter) diagnoseAssignmentNode(node AssignmentNode, curSymbols map if !ok { i.addUnknownDiagnostic(variable.Identifier, "variable") } + for _, selector := range variable.Selectors { + if selector.IndexNode != nil { + i.diagnoseExpression(selector.IndexNode.Index, curSymbols) + } else if selector.RangeNode != nil { + i.diagnoseExpression(selector.RangeNode.From, curSymbols) + i.diagnoseExpression(selector.RangeNode.To, curSymbols) + } + } } // also check the right hand side i.diagnoseExpression(node.Value, knownSymbols) diff --git a/server/internal/lang/parser.go b/server/internal/lang/parser.go index 17ab0f8..7b6d160 100644 --- a/server/internal/lang/parser.go +++ b/server/internal/lang/parser.go @@ -37,11 +37,15 @@ type DirectiveNode struct { DefineNode *DefineNode } type AssignmentNode struct { - Variables []VariableNode + Variables []AssignmentVariableNode Value ExprNode IsAssign bool IsDelayedAssign bool // true if used <= instead of = } +type AssignmentVariableNode struct { + Identifier Token + Selectors []SelectorNode +} type IndexNode struct { Index ExprNode } @@ -697,7 +701,7 @@ func (p *Parser) parseVariableNode(tokens []Token, pos int) (result VariableNode newPos = pos return } -func (p *Parser) parseAssignables(tokens []Token, pos int) (result []VariableNode, newPos int, err error) { +func (p *Parser) parseAssignables(tokens []Token, pos int) (result []AssignmentVariableNode, newPos int, err error) { // -> [LCURL] {COMMA } [RCURL] potentialPos, e := p.checkToken("assignables", []string{"lcurl"}, pos, tokens) // it's ok if it fails since it's optional @@ -708,7 +712,7 @@ func (p *Parser) parseAssignables(tokens []Token, pos int) (result []VariableNod } // get the first assignable - assignable, potentialPos, e := p.parseVariableNode(tokens, pos) + assignable, potentialPos, e := p.parseAssignableVariable(tokens, pos) if e != nil { // first must succeed err = e return @@ -718,7 +722,7 @@ func (p *Parser) parseAssignables(tokens []Token, pos int) (result []VariableNod // now try taking the rest potentialPos, e = p.checkToken("assignables", []string{"comma"}, pos, tokens) for e == nil { - assignable, potentialPos, e = p.parseVariableNode(tokens, potentialPos+1) + assignable, potentialPos, e = p.parseAssignableVariable(tokens, potentialPos+1) if e != nil { err = e return @@ -740,6 +744,25 @@ func (p *Parser) parseAssignables(tokens []Token, pos int) (result []VariableNod return } +func (p *Parser) parseAssignableVariable(tokens []Token, pos int) (result AssignmentVariableNode, newPos int, err error) { + // -> {} + pos, err = p.checkToken("assignmentvariable", []string{"identifier"}, pos, tokens) + if err != nil { + return + } + result.Identifier = tokens[pos] + pos++ + + // take selectors + selector, potentialPos, e := p.parseSelectorNode(tokens, pos) + for e == nil { + result.Selectors = append(result.Selectors, selector) + pos = potentialPos + selector, potentialPos, e = p.parseSelectorNode(tokens, pos) + } + newPos = pos + return +} func (p *Parser) parseAssignmentNodeWithoutSemicolon(tokens []Token, pos int) (result AssignmentNode, newPos int, err error) { // -> [ASSIGN] (EQUAL | <=) potentialPos, e := p.checkToken("assignment", []string{"assign"}, pos, tokens) @@ -2046,6 +2069,7 @@ Grammar: -> TASK SEMICOLON ENDTASK [SEMICOLON] -> [LCURL] {COMMA } [RCURL] + -> {} -> [ASSIGN] (EQUAL | <=) -> SEMICOLON -> {}