func parseFunctionDeclarationArguments(tokens []*lexer.Token) ([]string, int, error) { var args []string if len(tokens) == 0 || !tokens[0].IsTypeAndData(lexer.TOKEN_SEPARATOR, "(") { return args, 0, nil } var i int for i = 1; i < len(tokens)-1; i++ { if tokens[i].IsTypeAndData(lexer.TOKEN_SEPARATOR, ")") { break } args = append(args, tokens[i].Data) } if !tokens[i].IsTypeAndData(lexer.TOKEN_SEPARATOR, ")") { return nil, 0, util.NewSyntaxError("expected an )", tokens[i].Line, tokens[i].Column, tokens[i].File) } i++ return args, i, nil }
func parseBlock(tokens []*lexer.Token) ([]*lexer.Token, int, error) { var block []*lexer.Token var i int depth := 0 for i = 0; i < len(tokens); i++ { if tokens[i].IsOpening() { depth++ } else if tokens[i].IsClosing() { depth-- if depth == 0 { break } } if i > 0 { block = append(block, tokens[i]) } } if depth != 0 { return nil, 0, util.NewSyntaxError("unclosed block", tokens[i-1].Line, tokens[i-1].Column, tokens[i-1].File) } return block, i, nil }
func (n *PushNode) Eval(block *Block) (*Value, error) { switch n.Token.Type { case lexer.TOKEN_NUMBER: num := big.NewRat(0, 1) _, ok := num.SetString(n.Token.Data) if !ok { return nil, util.NewSyntaxError("malformed number", n.Token.Line, n.Token.Column, n.Token.File) } return NewValueFromRat(num), nil case lexer.TOKEN_STRING_SINGLE: return NewValueFromString(n.Token.Data), nil case lexer.TOKEN_STRING_DOUBLE: var newString string parts := strings.Split(n.Token.Data, " ") for i, part := range parts { if len(part) > 0 && part[0] == '$' { name := part[1:] if block.Scope.GetSymbol(name) == nil { return nil, util.NewSyntaxError("symbol "+name+" doesn't exist in scope", n.Token.Line, n.Token.Column, n.Token.File) } else { newString += block.Scope.GetSymbol(name).Value.String() } } else { newString += part } if i != len(parts)-1 { newString += " " } } return NewValueFromString(newString), nil case lexer.TOKEN_IDENTIFIER: name := n.Token.Data escaped := false if name[0] == '\\' { name = name[1:] escaped = true } symbol := block.Scope.GetSymbol(name) if symbol == nil { return nil, util.NewSyntaxError("symbol "+name+" doesn't exist in scope", n.Token.Line, n.Token.Column, n.Token.File) } value := symbol.Value if escaped { if value.Type != VALUE_FUNCTION { return nil, util.NewSyntaxError("expected a function", n.Token.Line, n.Token.Column, n.Token.File) } } else if value.Type == VALUE_FUNCTION && value.F.Type != FUNCTION_LAMBDA { return nil, value.F.Exec(block, n.Token) } return value, nil } return nil, nil }
func Nodes(tokens []*lexer.Token) ([]Node, error) { var nodes []Node for i := 0; i < len(tokens); i++ { token := tokens[i] switch token.Type { case lexer.TOKEN_IDENTIFIER: if token.IsDirective() { block, increase, err := parseBlock(tokens[i:]) if err != nil { return nil, err } i += increase nodes = append(nodes, &DirectiveNode{NameToken: token, Tokens: block}) } else { nodes = append(nodes, &PushNode{Token: token}) } case lexer.TOKEN_STRING_SINGLE, lexer.TOKEN_STRING_DOUBLE, lexer.TOKEN_NUMBER: nodes = append(nodes, &PushNode{Token: token}) case lexer.TOKEN_SEPARATOR: switch token.Data { case "[": block, increase, err := parseBlock(tokens[i:]) if err != nil { return nil, err } i += increase blockNodes, err := Nodes(block) if err != nil { return nil, err } nodes = append(nodes, &BlockNode{Nodes: blockNodes}) case "{": list, increase, err := parseBlock(tokens[i:]) if err != nil { return nil, err } i += increase listNodes, err := Nodes(list) if err != nil { return nil, err } nodes = append(nodes, &ListNode{Nodes: listNodes}) default: return nil, util.NewSyntaxError("unexpected "+token.Data, token.Line, token.Column, token.File) } default: return nil, util.NewSyntaxError("unexpected "+token.Data, token.Line, token.Column, token.File) } } return nodes, nil }
func (n *DirectiveNode) Eval(block *Block) (*Value, error) { name := n.NameToken.Data[:len(n.NameToken.Data)-1] switch name { case KEYWORD_USING: for _, token := range n.Tokens { if token.Type != lexer.TOKEN_IDENTIFIER { return nil, util.NewSyntaxError("expected an identifier", token.Line, token.Column, token.File) } module := block.Scope.GetModule(token.Data) if module == nil { return nil, util.NewSyntaxError("module "+token.Data+" doesn't exist in scope", token.Line, token.Column, token.File) } for key, value := range module.Data { block.Scope.SetSymbolLocally(key, NewSymbol(value, true, false)) } } case KEYWORD_OUT: for _, token := range n.Tokens { if token.Type != lexer.TOKEN_IDENTIFIER { return nil, util.NewSyntaxError("expected an identifier", token.Line, token.Column, token.File) } name := token.Data if block.Scope.GetSymbol(name) == nil { return nil, util.NewSyntaxError("symbol "+name+" not found in scope", token.Line, token.Column, token.File) } block.Scope.GetSymbol(name).Exported = true } case KEYWORD_CONSTANT, KEYWORD_SYMBOL: if len(n.Tokens) == 0 { return nil, util.NewSyntaxError("missing symbol name", n.NameToken.Line, n.NameToken.Column, n.NameToken.File) } if n.Tokens[0].Type != lexer.TOKEN_IDENTIFIER { return nil, util.NewSyntaxError("expected an identifier", n.Tokens[0].Line, n.Tokens[0].Column, n.Tokens[0].File) } name := n.Tokens[0].Data if block.Scope.GetSymbol(name) != nil && block.Scope.GetSymbol(name).Const == true { return nil, util.NewSyntaxError("cannot modify constant "+name, n.Tokens[0].Line, n.Tokens[0].Column, n.Tokens[0].File) } nodes, err := Nodes(n.Tokens[1:]) if err != nil { return nil, err } valueBlock := NewBlock(nodes, block, block.File) err = valueBlock.Exec() if err != nil { return nil, err } if valueBlock.Stack.Len() != 1 { return nil, util.NewSyntaxError(fmt.Sprintf("exact 1 value on the stack expected, tried to declare %d value(s)", valueBlock.Stack.Len()), n.NameToken.Line, n.NameToken.Column, n.NameToken.File) } block.Scope.SetSymbolLocally(name, NewSymbol(valueBlock.Stack.Pop().(*Value), n.NameToken.Data == KEYWORD_CONSTANT, false)) case "": if len(n.Tokens) == 0 { return nil, util.NewSyntaxError("missing function name", n.NameToken.Line, n.NameToken.Column, n.NameToken.File) } if n.Tokens[0].Type != lexer.TOKEN_IDENTIFIER { return nil, util.NewSyntaxError("expected an identifier for the function name", n.Tokens[0].Line, n.Tokens[0].Column, n.Tokens[0].File) } name := n.Tokens[0].Data if block.Scope.GetSymbol(name) != nil && block.Scope.GetSymbol(name).Const == true { return nil, util.NewSyntaxError("cannot modify constant "+name, n.Tokens[0].Line, n.Tokens[0].Column, n.Tokens[0].File) } args, increase, err := parseFunctionDeclarationArguments(n.Tokens[1:]) if err != nil { return nil, err } nodes, err := Nodes(n.Tokens[1+increase : len(n.Tokens)]) if err != nil { return nil, err } block.Scope.SetSymbolLocally(name, NewSymbol(NewValueFromFunction(&Function{ Type: FUNCTION_DECLARED, Name: name, Args: args, D: NewBlock(nodes, block, block.File), }), false, false)) default: return nil, util.NewSyntaxError("unknown directive "+n.NameToken.Data, n.NameToken.Line, n.NameToken.Column, n.NameToken.File) } return nil, nil }