Esempio n. 1
0
func primProcedureParams(e Env, head ast.Node, args []ast.Node) ast.Node {
	arg := args[0]
	switch val := arg.(type) {
	case *Procedure:
		return ast.NewList(val.Parameters)
	default:
		panicEvalError(args[0], "Argument to 'routine-params' not a procedure: "+arg.String())
	}

	return nil
}
Esempio n. 2
0
func primNow(e Env, head ast.Node, args []ast.Node) ast.Node {

	t := time.Now()
	year, month, day := t.Date()
	hour, minute, second := t.Clock()

	result := ast.NewList([]ast.Node{
		&ast.Number{Value: float64(year)},
		&ast.Number{Value: float64(month)},
		&ast.Number{Value: float64(day)},
		&ast.Number{Value: float64(hour)},
		&ast.Number{Value: float64(minute)},
		&ast.Number{Value: float64(second)},
	})

	return result
}
Esempio n. 3
0
func evalInvokeProcedure(dynamicEnv Env, f *Procedure, head ast.Node, unevaledArgs ast.Nodes, shouldEvalMacros bool) packet {
	defer func() {
		if e := recover(); e != nil {
			switch errorValue := e.(type) {
			case *EvalError:
				fmt.Printf("TRACE: (%v: %v): call to %v\n", head.Loc().Filename, head.Loc().Line, f.Name)
				panic(errorValue)
			default:
				panic(errorValue)
			}
		}
	}()

	// Validate parameters
	isVariableNumberOfParams := false
	for _, param := range f.Parameters {
		switch paramVal := param.(type) {
		case *ast.Symbol:
			if paramVal.Name == "&rest" {
				isVariableNumberOfParams = true
			}
		default:
			panicEvalError(head, "Procedure parameters should only be symbols: "+param.String())
		}
	}
	if !isVariableNumberOfParams {
		if len(unevaledArgs) != len(f.Parameters) {
			panicEvalError(head, fmt.Sprintf(
				"Procedure '%v' expects %v argument(s), but was given %v. Procedure parameter list: %v. Arguments: %v.",
				f.Name,
				len(f.Parameters),
				len(unevaledArgs),
				f.Parameters,
				unevaledArgs))
		}
	}

	// Create the lexical environment based on the procedure's lexical parent
	lexicalEnv := NewMapEnv(f.Name, f.ParentEnv)

	// Prepare the arguments for application
	var args []ast.Node
	if f.IsMacro {
		args = unevaledArgs
	} else {
		args = evalEachNode(dynamicEnv, unevaledArgs)
	}

	// Map arguments to parameters
	isMappingRestArgs := false
	iarg := 0
	for iparam, param := range f.Parameters {
		paramName := toSymbolName(param)
		if isMappingRestArgs {
			restArgs := args[iarg:]
			restList := ast.NewList(restArgs)
			lexicalEnv.Set(paramName, restList)
		} else if paramName == "&rest" {
			isMappingRestArgs = true
		} else {
			lexicalEnv.Set(paramName, args[iparam])
			iarg++
		}
	}

	if f.IsMacro {
		expandedMacro := trampoline(func() packet {
			return evalNode(lexicalEnv, f.Body)
		})

		if shouldEvalMacros {
			return bounce(func() packet {
				// This is executed in the environment of its application, not the
				// environment of its definition
				return evalNode(dynamicEnv, expandedMacro)
			})
		} else {
			return respond(expandedMacro)
		}
	} else {
		// Evaluate the body in the new lexical environment
		return bounce(func() packet {
			return evalNode(lexicalEnv, f.Body)
		})
	}
}