예제 #1
0
파일: builtin.go 프로젝트: wellington/sass
func (d *desc) Visit(node ast.Node) ast.Visitor {
	switch v := node.(type) {
	case *ast.RuleSpec:
		for i := range v.Values {
			ast.Walk(d, v.Values[i])
		}
	case *ast.GenDecl:
		for _, spec := range v.Specs {
			ast.Walk(d, spec)
		}
		return nil
	case *ast.CallExpr:
		d.c.name = v.Fun.(*ast.Ident).Name
		for _, arg := range v.Args {
			switch v := arg.(type) {
			case *ast.KeyValueExpr:
				d.c.params = append(d.c.params, v)
			case *ast.Ident:
				d.c.params = append(d.c.params, &ast.KeyValueExpr{
					Key: v,
				})
			default:
				panic(fmt.Errorf("%s failed to parse arg % #v\n",
					d.c.name, v))
			}
		}
		return nil
	case nil:
		return nil
	default:
		panic(fmt.Errorf("illegal walk % #v\n", v))
	}
	return d
}
예제 #2
0
파일: compile.go 프로젝트: wellington/sass
func (ctx *Context) run(path string, src interface{}) ([]byte, error) {

	ctx.fset = token.NewFileSet()
	// ctx.mode = parser.Trace
	pf, err := parser.ParseFile(ctx.fset, path, src, ctx.mode)
	if err != nil {
		return nil, err
	}

	ast.Walk(ctx, pf)
	lr, _ := utf8.DecodeLastRune(ctx.buf.Bytes())
	_ = lr
	if ctx.buf.Len() > 0 && lr != '\n' {
		ctx.out("\n")
	}
	// ctx.printSels(pf.Decls)
	return ctx.buf.Bytes(), nil
}
예제 #3
0
파일: builtin.go 프로젝트: wellington/sass
func register(s string, ch builtin.CallFunc, h builtin.CallHandle) {
	fset := token.NewFileSet()
	pf, err := ParseFile(fset, "", s, FuncOnly)
	if err != nil {
		if !strings.HasSuffix(err.Error(), "expected ';', found 'EOF'") {
			log.Fatal(err)
		}
	}
	d := &desc{c: call{
		ch:     ch,
		handle: h,
	}}
	ast.Walk(d, pf.Decls[0])
	if d.err != nil {
		log.Fatal("failed to parse func description", d.err)
	}
	if _, ok := builtins[d.c.name]; ok {
		log.Println("already registered", d.c.name)
	}
	builtins[d.c.name] = d.c
}
예제 #4
0
파일: compile.go 프로젝트: wellington/sass
// Visit is an internal compiler method. It is exported to allow ast.Walk
// to walk through the parser AST tree.
func (ctx *Context) Visit(node ast.Node) ast.Visitor {
	if ctx.err != nil {
		fmt.Println(ctx.err)
		return nil
	}
	var key ast.Node
	switch v := node.(type) {
	case *ast.BlockStmt:
		if (ctx.scope.RuleLen() > 0 || ctx.activeMedia != nil) &&
			!ctx.hiddenBlock {
			ctx.level = ctx.level + 1
			if !ctx.firstRule {
				fmt.Fprintf(ctx.buf, " }\n")
			}
		}
		ctx.scope = NewScope(ctx.scope)
		if !ctx.hiddenBlock {
			ctx.firstRule = true
		}
		for _, node := range v.List {
			ast.Walk(ctx, node)
		}
		if ctx.level > 0 {
			ctx.level = ctx.level - 1
		}
		ctx.scope = CloseScope(ctx.scope)
		if !ctx.hiddenBlock {
			ctx.blockOutro()
			ctx.firstRule = true
		}
		ctx.hiddenBlock = false
		// ast.Walk(ctx, v.List)
		// fmt.Fprintf(ctx.buf, "}")
		return nil
	case *ast.SelDecl:
	case *ast.File, *ast.GenDecl, *ast.Value:
		// Nothing to print for these
	case *ast.Ident:
		// The first IDENT is always the filename, just preserve
		// it somewhere
		key = ident
	case *ast.PropValueSpec:
		key = propSpec
	case *ast.DeclStmt:
		key = declStmt
	case *ast.IncludeSpec:
		// panic("not supported")
	case *ast.ValueSpec:
		key = valueSpec
	case *ast.RuleSpec:
		key = ruleSpec
	case *ast.SelStmt:
		// We will need to combine parent selectors
		// while printing these
		key = selStmt
		// Nothing to do
	case *ast.CommStmt:
	case *ast.CommentGroup:
	case *ast.Comment:
		key = comment
	case *ast.FuncDecl:
		ctx.printers[funcDecl](ctx, node)
		// Do not traverse mixins in the regular context
		return nil
	case *ast.BasicLit:
		return ctx
	case *ast.CallExpr:
	case nil:
		return ctx
	case *ast.MediaStmt:
		fmt.Println("mediastmt")
		key = mediaStmt
	case *ast.EmptyStmt:
	case *ast.AssignStmt:
		key = assignStmt
	case *ast.EachStmt:
		key = eachStmt
	case *ast.ListLit:
	case *ast.ImportSpec:
	case *ast.IfDecl:
	case *ast.IfStmt:
		key = ifStmt
	default:
		fmt.Printf("add printer for: %T\n", v)
		fmt.Printf("% #v\n", v)
	}
	ctx.printers[key](ctx, node)
	return ctx
}
예제 #5
0
파일: include.go 프로젝트: wellington/sass
func printInclude(ctx *Context, n ast.Node) {
	panic("dont call this")
	spec := n.(*ast.IncludeSpec)

	name := spec.Name.String()
	var params []*ast.Field
	if spec.Params != nil {
		params = spec.Params.List
	}
	numargs := spec.Params.NumFields()

	mix, err := ctx.scope.Mixin(name, numargs)
	if err != nil {
		log.Fatal(err)
	}

	// Add new scope, register args
	ctx.scope = NewScope(ctx.scope)

	mixargs := mix.fn.Type.Params.List
	for i := range mixargs {
		// Param passed by include
		var param *ast.Field
		if len(params) > i {
			param = params[i]
		}
		var (
			key *ast.BasicLit
			val *ast.Ident
		)
		_, _ = key, val
		switch v := mixargs[i].Type.(type) {
		case *ast.BasicLit:
			key = v
		case *ast.KeyValueExpr:
			key = v.Key.(*ast.BasicLit)
			val = ast.ToIdent(v.Value)
		}

		if param != nil {
			switch v := param.Type.(type) {
			case *ast.KeyValueExpr:
				// Key args specify their argument, so use their key
				// instead of the mixins argument for this position
				// Params with defaults
				key = v.Key.(*ast.BasicLit)
				val = ast.ToIdent(v.Value)
			case *ast.Ident:
				val = v
			case *ast.BasicLit:
				val = ast.ToIdent(v)
			default:
				fmt.Printf("dropped param: % #v\n", v)
			}
		}
		// if key != nil && val != nil {
		// 	ctx.scope.Insert(key.Value, val.Name)
		// }
	}
	if len(params) > len(mixargs) {
		fmt.Printf("dropped extra params: % #v\n", params[len(mixargs):])
	}

	for _, stmt := range mix.fn.Body.List {
		ast.Walk(ctx, stmt)
	}

	// Exit new scope, removing args
	ctx.scope = CloseScope(ctx.scope)
}