예제 #1
0
파일: expand.go 프로젝트: luoxing91/goLisp
// expand definition formals to pairs
func ExpandFormals(nodes []ast.Node) ast.Node {
	//(1).
	//  (define (<variable> <formals>) <body>) equivalent to
	//  (define <variable>
	//    (lambda (<formals>) <body>))
	//(2).
	//  (define (<variable> . <formal>) <body>) equivalent to
	//    <formal> should be a single variable
	//  (define <variable>
	//    (lambda <formal> <body>))

	prev := ast.NewPair(nil, nil)
	curr := ast.NewPair(nil, nil)

	front := prev
	dotted := false

	exists := make(map[string]bool)

	for i, node := range nodes {
		switch node.(type) {
		case *ast.Name:
			id := node.(*ast.Name).Identifier
			if id == "." {
				dotted = true
				if i+1 == len(nodes) {
					panic(fmt.Sprint("unexpected `)' after dot"))
				}
			} else {
				if _, ok := exists[id]; ok {
					panic(fmt.Sprint("duplicate argument identifier: ", node))
				} else {
					exists[id] = true
				}
				if dotted {
					prev.Second = node
					// should be the last element
					if i+1 < len(nodes) {
						panic(fmt.Sprint("illegal use of `.'"))
					}
				} else {
					curr.First = node
					prev.Second = curr
					prev = curr
					curr = ast.NewPair(nil, nil)
				}
			}
		default:
			panic(fmt.Sprint("illegal argument type: ", node))
		}
	}
	return front.Second
}
예제 #2
0
파일: expand.go 프로젝트: luoxing91/goLisp
func ExpandList(nodes []ast.Node) ast.Node {
	prev := ast.NewPair(nil, nil)
	curr := ast.NewPair(nil, nil)

	front := prev
	dotted := false

	for i, node := range nodes {
		isdot := false
		expanded := node

		switch node.(type) {
		case *ast.Name:
			id := node.(*ast.Name).Identifier
			if id == "." {
				isdot = true
				dotted = true
				if i == 0 || i+2 != len(nodes) {
					panic(fmt.Sprint("illegal use of `.'"))
				}
			}
		case *ast.Tuple:
			elements := node.(*ast.Tuple).Elements
			expanded = ExpandList(elements)
		default:
		}
		if !isdot {
			if dotted {
				prev.Second = expanded
			} else {
				prev.Second = curr
				curr.First = expanded
				prev = curr
				curr = ast.NewPair(nil, nil)
			}
		}
	}
	return front.Second
}