func primConcat(e Env, head ast.Node, args []ast.Node) ast.Node { var sum ast.Node for _, arg := range args { if sum == nil { sum = arg } else { switch sumVal := sum.(type) { case ast.Coll: switch argVal := arg.(type) { case ast.Coll: sum = sumVal.Append(argVal) default: panicEvalError(arg, "Cannot concat a collection with a non-collection: "+arg.String()) } default: panicEvalError(arg, "Cannot concat a non-collection type: "+sum.String()) } } } if sum == nil { return &ast.Nil{} } else { return sum } }
func ensureSymbol(n ast.Node) *ast.Symbol { if v, ok := n.(*ast.Symbol); ok { return v } panic("Expected symbol: " + n.String()) }
func ensureList(n ast.Node) *ast.List { if v, ok := n.(*ast.List); ok { return v } panic("Expected list: " + n.String()) }
func panicEvalError(n ast.Node, s string) { var loc *token.Location if n != nil { loc = n.Loc() } panic(NewEvalError(s, loc)) }
func toSymbolName(n ast.Node) string { switch value := n.(type) { case *ast.Symbol: return value.Name } panic("Not a symbol: " + n.String()) }
func toListValue(n ast.Node) *ast.List { switch value := n.(type) { case *ast.List: return value } panicEvalError(n, "Expression is not a list: "+n.String()) return nil }
func toSymbolValue(n ast.Node) string { switch value := n.(type) { case *ast.Symbol: return value.Name } panicEvalError(n, "Expression is not a symbol: "+n.String()) return "" }
func toNumberValue(n ast.Node) float64 { switch value := n.(type) { case *ast.Number: return value.Value } panicEvalError(n, "Expression is not a number: "+n.String()) return 0.0 }
func testInputFile(sourceFilePath string, t *testing.T) { sourceDirPart, sourceFileNamePart := filepath.Split(sourceFilePath) parts := strings.Split(sourceFileNamePart, ".") testName := parts[0] outputFilePath := sourceDirPart + testName + ".out" input, errIn := util.ReadFile(sourceFilePath) if errIn != nil { t.Errorf("Error reading file <" + sourceFilePath + ">: " + errIn.Error()) return } expectedRaw, errOut := util.ReadFile(outputFilePath) if errOut != nil { t.Errorf("Error reading file <" + outputFilePath + ">: " + errOut.Error()) return } // Remove any carriage return line endings from .out file expectedWithUntrimmed := strings.Replace(expectedRaw, "\r", "", -1) expected := strings.TrimSpace(expectedWithUntrimmed) nodes, errors := parser.Parse(input, sourceFilePath) if errors.Len() != 0 { verify(t, sourceFilePath, input, expected, errors.String()) } else { e := interpreter.NewTopLevelMapEnv() var outputBuffer bytes.Buffer var result ast.Node var evalError error for _, n := range nodes { result, evalError = interpreter.Eval(e, n, &outputBuffer) if evalError != nil { break } } actual := (&outputBuffer).String() if evalError == nil { //DEBUG fmt.Printf("RESULT(%v): %v\n", sourceFilePath, result) if result != nil { actual = actual + result.String() } } else { actual = actual + evalError.Error() } verify(t, sourceFilePath, input, expected, actual) } }
func specialCond(e Env, head ast.Node, args []ast.Node) packet { for i := 0; i < len(args); i += 2 { predicate := toBooleanValue(trampoline(func() packet { return evalNode(e, args[i]) })) if predicate { return bounce(func() packet { return evalNode(e, args[i+1]) }) } } panicEvalError(head, "No matching cond clause: "+head.String()) return respond(&ast.Nil{}) }
func (f *Function) Equals(n ast.Node) bool { panicEvalError(n, "Cannot compare the values of functions: "+ f.String()+" and "+n.String()) return false }
func (p *Primitive) Equals(n ast.Node) bool { panicEvalError(n, "Cannot compare the values of primitive procedures: "+ p.String()+" and "+n.String()) return false }
func (en *EnvNode) Equals(n ast.Node) bool { panicEvalError(n, "Cannot compare the values of environments: "+ en.String()+" and "+n.String()) return false }
func (c *Chan) Equals(n ast.Node) bool { panicEvalError(n, "Cannot compare the values of chans: "+ c.String()+" and "+n.String()) return false }
func (m *Macro) Equals(n ast.Node) bool { panicEvalError(n, "Cannot compare the values of macros: "+ m.String()+" and "+n.String()) return false }