Skip to content

Commit

Permalink
Merge pull request #21 from wellington/feature/builtin
Browse files Browse the repository at this point in the history
Feature/builtin
  • Loading branch information
drewwells committed Feb 11, 2016
2 parents ce93120 + f4efa0f commit ef8f72e
Show file tree
Hide file tree
Showing 276 changed files with 37,187 additions and 91 deletions.
65 changes: 65 additions & 0 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Godeps/Readme

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions README.md
Expand Up @@ -6,6 +6,17 @@ Pure Go sass scanner, ast, and parser

Cross platform compiler for Sass

# Usage

``` shell
go get -u github.com/wellington/sass/sass
```

``` shell
sass compile [-o file.css] input.scss
```


This project is currently in alpha, and contains no compiler. A scanner and parser are being developed to support a future compiler.

To help, check out [parser](https://github.com/wellington/sass/tree/master/parser). This project contains tests that iterate through sass-spec running the parser against example inputs. Errors detected by the parser are reported. However, you could also set the Parser mode to `Trace` and verify proper ast trees are being built from the input. As the parser matures, output can automatically be verified by the example outputs in these directories.
Expand Down Expand Up @@ -83,3 +94,10 @@ Passing 20 of the basic Sass tests in [sass-spec](https://github.com/sass/sass-s
- Function Directives :question:
- [ ] Extending Sass
- [ ] Defining Custom Sass Functions

### Builtin Funcs
Color functions only output hex strings for right now
- [x] rgb()
- [x] rgba()
- [x] mix()
- [x] invert()
1 change: 1 addition & 0 deletions ast/ast.go
Expand Up @@ -337,6 +337,7 @@ type (
Args []Expr // function arguments; or nil
Ellipsis token.Pos // position of "...", if any
Rparen token.Pos // position of ")"
Resolved *BasicLit
}

// A StarExpr node represents an expression of the form "*" Expression.
Expand Down
81 changes: 60 additions & 21 deletions builtin/color.go → builtin/colors/rgb.go
@@ -1,4 +1,4 @@
package builtin
package colors

import (
"fmt"
Expand All @@ -7,9 +7,17 @@ import (
"strconv"

"github.com/wellington/sass/ast"
"github.com/wellington/sass/builtin"
"github.com/wellington/sass/token"
)

func init() {
builtin.Register("rgb($red:0, $green:0, $blue:0)", rgb)
builtin.Register("rgba($red:0, $green:0, $blue:0, $alpha:0)", rgba)
builtin.Register("mix($color1:0, $color2:0, $weight:0.5)", mix)
builtin.Register("invert($color)", invert)
}

func resolveDecl(ident *ast.Ident) []*ast.BasicLit {
var lits []*ast.BasicLit
switch decl := ident.Obj.Decl.(type) {
Expand Down Expand Up @@ -77,8 +85,8 @@ func parseColors(args []*ast.BasicLit) (color.RGBA, error) {
return ret, err
}

func RGB(args []*ast.BasicLit) (*ast.BasicLit, error) {
fmt.Printf("red: %s green: %s blue: %s\n",
func rgb(args []*ast.BasicLit) (*ast.BasicLit, error) {
log.Printf("rgb args: red: %s green: %s blue: %s\n",
args[0].Value, args[1].Value, args[2].Value)
c, err := parseColors(args)
if err != nil {
Expand All @@ -91,27 +99,58 @@ func RGB(args []*ast.BasicLit) (*ast.BasicLit, error) {
return lit, nil
}

func RGBA(args []*ast.BasicLit) (*ast.BasicLit, error) {
fmt.Println("rgba", args)
func rgba(args []*ast.BasicLit) (*ast.BasicLit, error) {
log.Printf("rgba args: red: %s green: %s blue: %s alpha: %s\n",
args[0].Value, args[1].Value, args[2].Value, args[3].Value)

c, err := parseColors(args)
if err != nil {
return nil, err
}
_ = c
return nil, nil
// var last *ast.BasicLit
// switch v := args[len(args)-1].(type) {
// case *ast.BasicLit:
// last = v
// case *ast.KeyValueExpr:
// // Validate args
// last = v.Value.(*ast.BasicLit)
// }
lit := ast.BasicLitFromColor(c)
// There's some stupidity in the color stuff, do a lookup
// manually
lit.Value = ast.LookupColor(lit.Value)
return lit, nil
}

func mix(args []*ast.BasicLit) (*ast.BasicLit, error) {
fmt.Printf("mix:\narg0: % #v\narg1: % #v\narg2: % #v\n",
args[0], args[1], args[2])
// parse that weight
wt, err := strconv.ParseFloat(args[2].Value, 8)
// Parse percentage ie. 50%
if err != nil {
var i float64
_, err := fmt.Sscanf(args[2].Value, "%f%%", &i)
if err != nil {
log.Fatal(err)
}
wt = i / 100
}
c1 := ast.ColorFromHexString(args[0].Value)
c2 := ast.ColorFromHexString(args[1].Value)
var r, g, b, a float64
r = wt*float64(c1.R) + (1-wt)*float64(c2.R)
g = wt*float64(c1.G) + (1-wt)*float64(c2.G)
b = wt*float64(c1.B) + (1-wt)*float64(c2.B)
a = wt*float64(c1.A) + (1-wt)*float64(c2.A)
ret := color.RGBA{
R: uint8(r),
G: uint8(g),
B: uint8(b),
A: uint8(a),
}
lit := ast.BasicLitFromColor(ret)
return lit, nil
}

func invert(args []*ast.BasicLit) (*ast.BasicLit, error) {
c := ast.ColorFromHexString(args[0].Value)

c.R = 255 - c.R
c.G = 255 - c.G
c.B = 255 - c.B

// // strconv.FormatFloat(v, 'g', -1, 32)
// lit := &ast.BasicLit{
// Value: fmt.Sprintf("rgba(%d, %d, %d, %s)",
// c.R, c.G, c.B, last.Value),
// }
// return lit, nil
return ast.BasicLitFromColor(c), nil
}
25 changes: 25 additions & 0 deletions builtin/register.go
@@ -0,0 +1,25 @@
package builtin

import "github.com/wellington/sass/ast"

type CallHandler func(args []*ast.BasicLit) (*ast.BasicLit, error)

var reg func(s string, ch CallHandler)

var chs = map[string]CallHandler{}

func BindRegister(fn func(s string, ch CallHandler)) {
reg = fn
for k, v := range chs {
reg(k, v)
delete(chs, k)
}
}

func Register(s string, ch CallHandler) {
if reg != nil {
reg(s, ch)
} else {
chs[s] = ch
}
}
11 changes: 10 additions & 1 deletion circle.yml
@@ -1,6 +1,12 @@
machine:
environment:
GO15VENDOREXPERIMENT: 1
pre:
- go version
- go version | grep 1.5.3 || sudo rm -rf /usr/local/go
- wget https://storage.googleapis.com/golang/go1.5.3.linux-amd64.tar.gz
- sudo tar -C /usr/local -xzf go1.5.3.linux-amd64.tar.gz
- go version
post:
- mkdir -p ${GOPATH%%:*}/src/github.com/${CIRCLE_PROJECT_USERNAME}
- rm -rf ${GOPATH%%:*}/src/github.com/${CIRCLE_PROJECT_USERNAME}/*
Expand All @@ -11,7 +17,10 @@ dependencies:
override:
- git submodule update --init --recursive
test:
pre:
- go version
- go env
override:
- go test -race -short ./...
- go list -f '{{if len .TestGoFiles}}"go test -race -short {{.ImportPath}}"{{end}}' ./... | grep -v /vendor/ | xargs -L 1 sh -c
post:
- go list -f '{{if len .TestGoFiles}}"go test -covermode=count -short -coverprofile={{.Dir}}/.coverprofile {{.ImportPath}}"{{end}}' ./... | grep -v /vendor/ | xargs -L 1 sh -c
46 changes: 21 additions & 25 deletions compiler/compile.go
Expand Up @@ -2,7 +2,9 @@ package compiler

import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"strings"
"unicode/utf8"
Expand Down Expand Up @@ -30,7 +32,15 @@ type Context struct {
scope Scope
}

func fileRun(path string) (string, error) {
func File(path string, out string) error {
s, err := Run(path)
if err != nil {
return err
}
return ioutil.WriteFile(out, []byte(s), 0666)
}

func Run(path string) (string, error) {
ctx := &Context{}
ctx.Init()
out, err := ctx.Run(path)
Expand Down Expand Up @@ -59,7 +69,7 @@ func (ctx *Context) run(path string, src interface{}) (string, error) {
return ctx.buf.String(), nil
}

// Run takes a single Sass file and compiles it
// Run takes a single Sass file and compiles it outputing a string
func (ctx *Context) Run(path string) (string, error) {
return ctx.run(path, nil)
}
Expand Down Expand Up @@ -324,18 +334,12 @@ func calculateExprs(ctx *Context, bin *ast.BinaryExpr) (string, error) {
var err error
// Convert CallExpr to BasicLit
if cx, ok := x.(*ast.CallExpr); ok {
x, err = evaluateCall(cx)
if err != nil {
return "", fmt.Errorf("error execing %s: %s",
cx.Fun, err)
}
fmt.Printf("cx (%p) % #v\n", cx.Fun, cx.Fun.(*ast.Ident))
x = cx.Fun.(*ast.Ident).Obj.Decl.(ast.Expr)
}
if cy, ok := y.(*ast.CallExpr); ok {
y, err = evaluateCall(cy)
if err != nil {
return "", fmt.Errorf("error execing %s: %s",
cy.Fun, err)
}
fmt.Printf("cy (%p) % #v\n", cy.Fun, cy.Fun)
y = cy.Fun.(*ast.Ident).Obj.Decl.(ast.Expr)
}

if err != nil {
Expand Down Expand Up @@ -437,12 +441,7 @@ func resolveAssign(ctx *Context, astmt *ast.AssignStmt) (lits []*ast.BasicLit) {
// Replace Ident with underlying BasicLit
lits = append(lits, resolveAssign(ctx, assign)...)
case *ast.CallExpr:
// CallExpr needs to be evaluated before Ident is correctly resolved
lit, err := evaluateCall(v)
if err != nil {
log.Fatal(err)
}
lits = append(lits, lit)
lits = append(lits, v.Fun.(*ast.Ident).Obj.Decl.(*ast.BasicLit))
case *ast.BasicLit:
lits = append(lits, v)
default:
Expand All @@ -459,14 +458,11 @@ func resolveExpr(ctx *Context, expr ast.Expr) (out string, err error) {
case *ast.BinaryExpr:
out, err = calculateExprs(ctx, v)
case *ast.CallExpr:
s, err := evaluateCall(v)
if err != nil || s == nil {
for _, arg := range v.Args {
fmt.Println("arg", arg)
}
log.Fatalf("failed to call '%s': %s: % #v\n", v.Fun, err, v)
expr := v.Fun.(*ast.Ident).Obj.Decl.(*ast.BasicLit)
if expr == nil {
return "", errors.New("call return was nil")
}
out = s.Value
out = expr.Value
case *ast.ParenExpr:
out, ctx.err = simplifyExprs(ctx, []ast.Expr{v.X})
case *ast.Ident:
Expand Down

0 comments on commit ef8f72e

Please sign in to comment.