72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/wyst-lang/wyst/tokenizer"
|
|
)
|
|
|
|
func ParseString(code string) ([]AstNode, error) {
|
|
tokens, state, err := tokenizer.Tokenize(code)
|
|
ast, err1 := Parse(tokens, TOP_RULE)
|
|
if err != nil {
|
|
return ast, fmt.Errorf("LexingError at %d:%d: %s", state.Line, state.Column, err)
|
|
} else if err1 != nil {
|
|
return ast, fmt.Errorf("ParserError")
|
|
}
|
|
return ast, nil
|
|
}
|
|
|
|
func Parse(tokens []tokenizer.Token, rule_set []Rule) ([]AstNode, error) {
|
|
var ast = []AstNode{}
|
|
for i := 0; i < len(tokens); i++ {
|
|
for r := 0; r < len(rule_set); r++ {
|
|
matching := false
|
|
var match_nodes = []AstNode{}
|
|
if rule_set[r].Kind == RK_Port {
|
|
if tokens[i].Rule.Name == rule_set[r].Name {
|
|
matching = true
|
|
match_nodes = append(match_nodes, AstNode{Rule: rule_set[r], Value: tokens[i].Value})
|
|
}
|
|
} else {
|
|
for v := 0; v < len(rule_set[r].Inner); v++ {
|
|
if rule_set[r].Inner[v].Kind == RK_Required {
|
|
if len(tokens)-i > v && tokens[i].Rule.Name == rule_set[r].Inner[v].Name {
|
|
matching = true
|
|
match_nodes = append(match_nodes, AstNode{Rule: rule_set[r].Inner[v], Value: tokens[i].Value})
|
|
} else {
|
|
matching = false
|
|
break
|
|
}
|
|
} else if rule_set[r].Inner[v].Kind == RK_Repeat {
|
|
for l := 0; len(tokens)-i > l && tokens[i+l].Rule.Name == rule_set[r].Inner[v].Name; l++ {
|
|
match_nodes = append(match_nodes, AstNode{Rule: rule_set[r].Inner[v], Value: tokens[i+l].Value})
|
|
matching = true
|
|
}
|
|
} else if rule_set[r].Inner[v].Kind == RK_Optional {
|
|
match_nodes = append(match_nodes, AstNode{Rule: rule_set[r].Inner[v], Value: tokens[i].Value})
|
|
matching = true
|
|
}
|
|
}
|
|
}
|
|
if matching {
|
|
ast = append(ast, AstNode{Rule: rule_set[r], Inner: match_nodes, Value: merge_nodes(match_nodes)})
|
|
i += len(match_nodes) - 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return ast, nil
|
|
}
|
|
|
|
func merge_nodes(match_nodes []AstNode) string {
|
|
str := ""
|
|
for i := 0; i < len(match_nodes); i++ {
|
|
str += match_nodes[i].Value
|
|
if len(match_nodes) > i {
|
|
str += " "
|
|
}
|
|
}
|
|
return str
|
|
}
|