func runFile(name string) *parser.Block { os.Chdir(filepath.Dir(name)) file, err := util.NewFile(filepath.Base(name) + "." + util.FileExtension) if err != nil { reportError(err.Error(), false) } lex := lexer.NewLexerFromFile(file) err = lex.Lex() if err != nil { reportError(err.Error(), false) } nodes, err := parser.Nodes(lex.Tokens) if err != nil { reportError(err.Error(), false) } block := parser.NewBlock(nodes, nil, file) setDefaults(block.Scope) err = block.Exec() if err != nil { reportError(err.Error(), false) } return block }
func while_(context *parser.FunctionCallContext) error { values, err := parser.ValidateArguments(context, "while", parser.VALUE_FUNCTION, parser.VALUE_FUNCTION) if err != nil { return err } check := values[0].F recheck: fakeBlock := parser.NewBlock(nil, nil, nil) checkErr := check.Exec(fakeBlock, context.Token) if checkErr != nil { return checkErr } if fakeBlock.Stack.Len() != 1 || fakeBlock.Stack.Peek(0).(*parser.Value).Type != parser.VALUE_BOOL { return util.NewInvalidArgumentError("while", "the callback function provided to while must return 1 boolean value", context.Token.Line, context.Token.Column, context.Token.File) } if fakeBlock.Stack.Peek(0).(*parser.Value).B { runErr := values[1].F.Exec(context.Block, context.Token) if runErr != nil { return runErr } goto recheck } return nil }
func orN(context *parser.FunctionCallContext) error { values, err := parser.ValidateArguments(context, "or-n", parser.VALUE_FUNCTION) if err != nil { return err } fakeBlock := parser.NewBlock(nil, nil, nil) runErr := values[0].F.Exec(fakeBlock, context.Token) if runErr != nil { return runErr } result := false if fakeBlock.Stack.Len() >= 1 { for fakeBlock.Stack.Len() > 0 { value := fakeBlock.Stack.Pop().(*parser.Value) if value.Type != parser.VALUE_BOOL { return util.NewInvalidArgumentError("or-n", "expected a boolean in the function stack", context.Token.Line, context.Token.Column, context.Token.File) } result = result || value.B } } else { return util.NewInvalidArgumentError("or-n", "expected at least 2 values to compare in function stack", context.Token.Line, context.Token.Column, context.Token.File) } context.Block.Stack.Push(parser.NewValueFromBool(result)) return nil }
func useFile(context *parser.FunctionCallContext) error { values, err := parser.ValidateArguments(context, "use-file", parser.VALUE_STRING) if err != nil { return err } file, err := util.NewFile(values[0].S) if err != nil { return err } lex := lexer.NewLexerFromFile(file) err = lex.Lex() if err != nil { return err } nodes, err := parser.Nodes(lex.Tokens) if err != nil { return err } fileBlock := parser.NewBlock(nodes, context.Block, file) err = fileBlock.Exec() if err != nil { return err } for key, value := range fileBlock.Scope.Symbols { if value.Exported { context.Block.Scope.SetSymbol(key, value) } } fileBlock.Stack.PopAllToOtherStack(context.Block.Stack) return nil }
func runRepl() *parser.Block { var tokens []*lexer.Token depth := 0 block := parser.NewBlock(nil, nil, nil) setDefaults(block.Scope) for { reader := bufio.NewReader(os.Stdin) fmt.Print("> ") data, _ := reader.ReadString('\n') lex := lexer.NewLexer([]rune(data)) err := lex.Lex() if err != nil { reportError(err.Error(), true) } else { for _, token := range lex.Tokens { tokens = append(tokens, token) } for _, token := range lex.Tokens { if token.IsOpening() { depth++ } else if token.IsClosing() { depth-- } } if depth <= 0 { nodes, err := parser.Nodes(tokens) tokens = nil depth = 0 if err != nil { reportError(err.Error(), true) } else { block.Nodes = nodes err := block.Exec() if err != nil { reportError(err.Error(), true) } if block.Stack.Len() > 0 { fmt.Print(util.COLOR_YELLOW) for i := 0; i < block.Stack.Len(); i++ { fmt.Print(block.Stack.Peek(i).(*parser.Value).String() + " ") } fmt.Print(util.COLOR_RESET + "\n") } } } } } return block }
func switchFunction(context *parser.FunctionCallContext, fall bool, otherwise bool) error { functionName := "switch" if fall { functionName += "-fallthrough" } var otherwiseFunction *parser.Function if otherwise { valuesOtherwise, errOtherwise := parser.ValidateArguments(context, functionName, parser.VALUE_FUNCTION) if errOtherwise != nil { return errOtherwise } otherwiseFunction = valuesOtherwise[0].F } values, err := parser.ValidateArguments(context, functionName, parser.VALUE_FUNCTION) if err != nil { return err } conditionFunction := values[0].F fakeBlock := parser.NewBlock(nil, nil, nil) conditionsErr := conditionFunction.Exec(fakeBlock, context.Token) if conditionsErr != nil { return conditionsErr } if fakeBlock.Stack.Len()%2 != 0 { return util.NewInvalidArgumentError(functionName, "cannot switch because the stack of the function is unbalanced, missing condition or callback", context.Token.Line, context.Token.Column, context.Token.File) } any := false conditions := 0 for i := fakeBlock.Stack.Len() - 1; i >= 0; i-- { conditions++ condition := fakeBlock.Stack.Peek(i).(*parser.Value) if condition.Type != parser.VALUE_BOOL { return util.NewInvalidArgumentError(functionName, "expected a boolean condition for condition "+strconv.Itoa(conditions), context.Token.Line, context.Token.Column, context.Token.File) } i-- if condition.B { any = true callback := fakeBlock.Stack.Peek(i).(*parser.Value) if callback.Type != parser.VALUE_FUNCTION { return util.NewInvalidArgumentError(functionName, "expected a function callback for condition "+strconv.Itoa(conditions), context.Token.Line, context.Token.Column, context.Token.File) } runErr := callback.F.Exec(context.Block, context.Token) if runErr != nil { return runErr } if !fall { break } } } if otherwise && !any { otherwiseErr := otherwiseFunction.Exec(context.Block, context.Token) if otherwiseErr != nil { return otherwiseErr } } return nil }