func listMap(context *runtime.MacroCallContext) (*runtime.Value, error) { list, err := context.Block.EvalNode(context.Nodes[0]) if err != nil { return nil, err } if list.Type != runtime.ListValue { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "expected a list") } ident := context.Nodes[1].(*parser.IdentifierNode).Token.Data callback := context.Nodes[2] mappedList := runtime.NewListValue() for _, item := range list.List { b := runtime.NewBlock([]parser.Node{callback}, runtime.NewScope(context.Block.Scope)) b.Scope.SetSymbolLocally(ident, runtime.NewSymbol(item)) result, err := b.Eval() if err != nil { return nil, err } mappedList.List = append(mappedList.List, result) } return mappedList, nil }
func builtinFor(context *runtime.MacroCallContext) (*runtime.Value, error) { l, err := context.Block.EvalNode(context.Nodes[0]) if err != nil { return nil, err } if l.Type != runtime.ListValue { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "expected a list to iterate over") } var args []string for _, nameNode := range context.Nodes[1].(*parser.ListNode).Nodes { ident, isIdent := nameNode.(*parser.IdentifierNode) if isIdent { args = append(args, ident.Token.Data) } else { return nil, runtime.NewRuntimeError(nameNode.Pos(), "expected an identifier") } } if len(args) > 2 { return nil, runtime.NewRuntimeError(context.Nodes[1].Pos(), "too many arguments provided") } callbackBlock := runtime.NewBlock([]parser.Node{context.Nodes[2]}, runtime.NewScope(context.Block.Scope)) for i, item := range l.List { if len(args) >= 1 { callbackBlock.Scope.SetSymbol(args[0], runtime.NewSymbol(item)) } if len(args) == 2 { callbackBlock.Scope.SetSymbol(args[1], runtime.NewSymbol(runtime.NewNumberValueFromInt64(int64(i)))) } _, err := callbackBlock.Eval() if err != nil { return nil, err } } return runtime.Nil, nil }
func listReduce(context *runtime.MacroCallContext) (*runtime.Value, error) { list, err := context.Block.EvalNode(context.Nodes[0]) if err != nil { return nil, err } if list.Type != runtime.ListValue { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "expected a list") } if len(list.List) == 0 { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "empty list") } identLeft := context.Nodes[1].(*parser.IdentifierNode).Token.Data identRight := context.Nodes[2].(*parser.IdentifierNode).Token.Data callback := context.Nodes[3] reduced := list.List[0] for _, item := range list.List[1:] { b := runtime.NewBlock([]parser.Node{callback}, runtime.NewScope(context.Block.Scope)) b.Scope.SetSymbolLocally(identLeft, runtime.NewSymbol(reduced)) b.Scope.SetSymbolLocally(identRight, runtime.NewSymbol(item)) result, err := b.Eval() if err != nil { return nil, err } reduced = result } return reduced, nil }
func builtinDefmacro(context *runtime.MacroCallContext) (*runtime.Value, error) { name := context.Nodes[0].(*parser.IdentifierNode).Token.Data if name == "_" { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "disallowed macro name") } if context.Block.Scope.GetSymbol(name) != nil && context.Block.Scope.GetSymbol(name).Const { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "%s is a constant and cannot be modified", name) } argNodes := context.Nodes[1].(*parser.ListNode) var args []string callback := context.Nodes[2].(*parser.ListNode) if len(callback.Nodes) == 0 { return nil, runtime.NewRuntimeError(callback.Pos(), "empty macro body") } for _, argNode := range argNodes.Nodes { ident, ok := argNode.(*parser.IdentifierNode) if !ok { return nil, runtime.NewRuntimeError(argNode.Pos(), "expected an identifier") } args = append(args, ident.Token.Data) } macro := runtime.NewMacro(func(handlerContext *runtime.MacroCallContext) (*runtime.Value, error) { block := runtime.NewBlock([]parser.Node{callback}, runtime.NewScope(handlerContext.Block.Scope)) for i, arg := range args { block.Scope.SetSymbolLocally(arg, runtime.NewSymbol(runtime.NewQuotedValue(handlerContext.Nodes[i]))) } return block.Eval() }, false) context.Block.Scope.SetMacro(name, macro) return runtime.Nil, nil }
func builtinDef(context *runtime.MacroCallContext) (*runtime.Value, error) { name := context.Nodes[0].(*parser.IdentifierNode).Token.Data value, err := context.Block.EvalNode(context.Nodes[1]) if name == "_" { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "disallowed symbol name") } if err != nil { return nil, err } if context.Block.Scope.GetSymbol(name) != nil && context.Block.Scope.GetSymbol(name).Const { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "%s is a constant and cannot be modified", name) } sym := runtime.NewSymbol(value) sym.Const = context.Name == "defconst" context.Block.Scope.SetSymbol(name, sym) return value, nil }
func builtinDefun(context *runtime.MacroCallContext) (*runtime.Value, error) { name := context.Nodes[0].(*parser.IdentifierNode).Token.Data if name == "_" { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "disallowed function name") } if context.Block.Scope.GetSymbol(name) != nil && context.Block.Scope.GetSymbol(name).Const { return nil, runtime.NewRuntimeError(context.Nodes[0].Pos(), "%s is a constant and cannot be modified", name) } argNodes := context.Nodes[1].(*parser.ListNode) var args []string callback := context.Nodes[2].(*parser.ListNode) if len(callback.Nodes) == 0 { return nil, runtime.NewRuntimeError(callback.Pos(), "empty function body") } for _, argNode := range argNodes.Nodes { ident, ok := argNode.(*parser.IdentifierNode) if !ok { return nil, runtime.NewRuntimeError(argNode.Pos(), "expected an identifier") } args = append(args, ident.Token.Data) } function := runtime.NewDeclaredFunction([]parser.Node{callback}, name, args) functionValue := runtime.NewFunctionValue(function) context.Block.Scope.SetSymbol(name, runtime.NewSymbol(functionValue)) return functionValue, nil }
package builtin import ( "fmt" "github.com/raoulvdberge/risp/lexer" "github.com/raoulvdberge/risp/parser" "github.com/raoulvdberge/risp/runtime" "github.com/raoulvdberge/risp/util" "math/big" ) var Symbols = runtime.Symtab{ "t": runtime.NewSymbol(runtime.True), "f": runtime.NewSymbol(runtime.False), "nil": runtime.NewSymbol(runtime.Nil), "print": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinPrint, "print"))), "println": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinPrintln, "println"))), "list": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinList, "list"))), "string": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinString, "string"))), "+": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMath, "+"))), "-": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMath, "-"))), "*": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMath, "*"))), "/": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMath, "/"))), "=": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinEquals, "="))), "!=": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinNotEquals, "!="))), ">": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMathCmp, ">"))), ">=": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMathCmp, ">="))), "<": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMathCmp, "<"))), "<=": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinMathCmp, "<="))), "and": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinAnd, "and"))), "or": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(builtinOr, "or"))),
func (s *ReplSession) Run() { line := liner.NewLiner() defer line.Close() line.SetCtrlCAborts(true) line.SetCompleter(s.completer) if f, err := os.Open(history); err == nil { line.ReadHistory(f) f.Close() } for { prompt := "> " if s.depth > 0 { prompt += "(" + strconv.Itoa(s.depth) + ") " } data, err := line.Prompt(prompt) if err != nil { if err == liner.ErrPromptAborted { return } util.ReportError(err, false) } line.AppendHistory(data) if f, err := os.Create(history); err == nil { line.WriteHistory(f) f.Close() } l := lexer.NewLexer(lexer.NewSourceFromString("<repl>", data)) err = l.Lex() if err != nil { util.ReportError(err, true) } else { for _, t := range l.Tokens { s.tokens = append(s.tokens, t) s.depth += t.DepthModifier() } if s.depth <= 0 { p := parser.NewParser(s.tokens) err := p.Parse() s.tokens = nil s.depth = 0 if err != nil { util.ReportError(err, true) continue } for _, node := range p.Nodes { result, err := s.block.EvalNode(node) if err != nil { util.ReportError(err, true) continue } data := util.Yellow("===> " + result.String()) if resultType(result) != "" { data += " " + util.Yellow("("+resultType(result)+")") } fmt.Println(data) s.block.Scope.SetSymbolLocally("_", runtime.NewSymbol(result)) } } } } }
package strings import ( "github.com/raoulvdberge/risp/runtime" "github.com/raoulvdberge/risp/util" "strings" "unicode" ) var Symbols = runtime.Symtab{ "range": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsRange, "range"))), "trim": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsTrim, "trim"))), "rune-at": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsRuneAt, "rune-at"))), "length": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsLength, "length"))), "format": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsFormat, "format"))), "split": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsSplit, "split"))), "replace": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsReplace, "replace"))), "reverse": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsReverse, "reverse"))), "contains": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsContains, "contains"))), "lower": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsLower, "lower"))), "upper": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsUpper, "upper"))), "is-digit": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsCharacterCheck, "is-digit"))), "is-letter": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsCharacterCheck, "is-letter"))), "is-lower": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsCharacterCheck, "is-lower"))), "is-upper": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(stringsCharacterCheck, "is-upper"))), } func stringsRange(context *runtime.FunctionCallContext) (*runtime.Value, error) { if err := runtime.ValidateArguments(context, runtime.StringValue, runtime.NumberValue, runtime.NumberValue); err != nil { return nil, err }
package math import ( "github.com/raoulvdberge/risp/runtime" "math" ) var Symbols = runtime.Symtab{ "mod": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathMod, "mod"))), "sqrt": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "sqrt"))), "sin": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "sin"))), "cos": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "cos"))), "tan": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "tan"))), "ceil": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "ceil"))), "floor": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "floor"))), "abs": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "abs"))), "log": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "log"))), "log10": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathSimpleMath, "log10"))), "pow": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathPow, "pow"))), "deg2rad": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathDeg2Rad, "deg2rad"))), "rad2deg": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(mathRad2Deg, "rad2deg"))), "pi": runtime.NewSymbol(runtime.NewNumberValueFromFloat64(math.Pi)), "e": runtime.NewSymbol(runtime.NewNumberValueFromFloat64(math.E)), } func mathMod(context *runtime.FunctionCallContext) (*runtime.Value, error) { if err := runtime.ValidateArguments(context, runtime.NumberValue, runtime.NumberValue); err != nil { return nil, err } return runtime.NewNumberValueFromInt64(context.Args[0].NumberToInt64() % context.Args[1].NumberToInt64()), nil
package list import "github.com/raoulvdberge/risp/runtime" var Symbols = runtime.Symtab{ "seq": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listSeq, "seq"))), "contains": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listContains, "contains"))), "contains-key": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listContainsKey, "contains-key"))), "push": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listPush, "push"))), "push-left": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listPushLeft, "push-left"))), "size": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listSize, "size"))), "get": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listGet, "get"))), "get-key": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listGetKey, "get-key"))), "set": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listSet, "set"))), "set-key": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listSetKey, "set-key"))), "drop": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listDrop, "drop"))), "drop-left": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listDropLeft, "drop-left"))), "join": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listJoin, "join"))), "range": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listRange, "range"))), "reverse": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listReverse, "reverse"))), "remove": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listRemove, "remove"))), "remove-key": runtime.NewSymbol(runtime.NewFunctionValue(runtime.NewBuiltinFunction(listRemoveKey, "remove-key"))), } func listSeq(context *runtime.FunctionCallContext) (*runtime.Value, error) { if err := runtime.ValidateArguments(context, runtime.NumberValue, runtime.NumberValue); err != nil { return nil, err } low := context.Args[0].NumberToInt64() high := context.Args[1].NumberToInt64()