예제 #1
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #2
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #3
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #4
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #5
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #6
0
파일: macros.go 프로젝트: raoulvdberge/risp
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
}
예제 #7
0
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"))),
예제 #8
0
파일: repl.go 프로젝트: raoulvdberge/risp
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))
				}
			}
		}
	}
}
예제 #9
0
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
	}
예제 #10
0
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
예제 #11
0
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()