Пример #1
0
func run(source lexer.Source) {
	l := lexer.NewLexer(source)
	util.Timed("lexing", *debug, func() {
		util.ReportError(l.Lex(), false)
	})

	p := parser.NewParser(l.Tokens)
	util.Timed("parsing", *debug, func() {
		util.ReportError(p.Parse(), false)
	})

	if *ast {
		bytes, _ := json.MarshalIndent(p, "", "    ")

		fmt.Println(string(bytes))
	} else {
		b := apply(runtime.NewBlock(p.Nodes, runtime.NewScope(nil)))

		util.Timed("runtime", *debug, func() {
			_, err := b.Eval()

			if err != nil {
				util.ReportError(err, false)
			}
		})
	}
}
Пример #2
0
func main() {
	flag.Usage = usage
	flag.Parse()

	if len(flag.Args()) > 0 {
		var file *util.File

		util.Timed("file reading", *debug, func() {
			os.Chdir(filepath.Dir(flag.Arg(0)))

			f, err := util.NewFile(filepath.Base(flag.Arg(0)))

			if err != nil {
				util.ReportError(err, false)
			}

			file = f
		})

		run(lexer.NewSourceFromFile(file))
	} else if *runRepl {
		s := repl.NewReplSession(apply(runtime.NewBlock(nil, runtime.NewScope(nil))))
		s.Run()
	} else {
		bytes, err := ioutil.ReadAll(os.Stdin)

		if err != nil {
			util.ReportError(err, false)
		}

		run(lexer.NewSourceFromString("<stdin>", string(bytes)))
	}
}
Пример #3
0
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
}
Пример #4
0
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
}
Пример #5
0
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
}
Пример #6
0
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
}
Пример #7
0
func builtinLoad(context *runtime.FunctionCallContext) (*runtime.Value, error) {
	if err := runtime.ValidateArguments(context, runtime.StringValue); err != nil {
		return nil, err
	}

	file, err := util.NewFile(context.Args[0].Str)

	if err != nil {
		return nil, err
	}

	l := lexer.NewLexer(lexer.NewSourceFromFile(file))
	util.ReportError(l.Lex(), false)

	p := parser.NewParser(l.Tokens)
	util.ReportError(p.Parse(), false)

	b := runtime.NewBlock(p.Nodes, runtime.NewScope(context.Block.Scope))

	result, err := b.Eval()

	if err != nil {
		return nil, err
	}

	for key, value := range b.Scope.Symbols {
		if value.Exported {
			if value.Value.Type == runtime.FunctionValue {
				value.Value.Function.CustomScope = b.Scope
			}

			context.Block.Scope.SetSymbol(b.SymbolName(key), value)
		}
	}

	return result, nil
}