func TestLightenFunctionExpression(t *testing.T) { e := expression{} e.addValue("lighten", typeFunction) rgba, err := color.Parse("#ff20f0") assert.NoError(t, err) e.addValue(rgba, typeColor) e.addValue(float64(10), typeNum) e.addValue(nil, typeFunctionEnd) v, err := e.evaluate() if err != nil { t.Error(err) } assert.Equal(t, "#fe53f3", v.(color.RGBA).Hex()) }
func (d *Decoder) value(tok *token) { switch tok.t { case tokenString: d.expr.addValue(tok.value[1:len(tok.value)-1], typeString) case tokenNumber: v, err := strconv.ParseFloat(tok.value, 64) if err != nil { d.error(d.pos(tok), "invalid float %v: %s", v, err) } d.expr.addValue(v, typeNum) case tokenPercentage: v, err := strconv.ParseFloat(tok.value[:len(tok.value)-1], 64) if err != nil { d.error(d.pos(tok), "invalid float %v: %s", v, err) } d.expr.addValue(v, typePercent) case tokenIdent: switch tok.value { case "true": d.expr.addValue(true, typeBool) case "false": d.expr.addValue(false, typeBool) case "null": d.expr.addValue(nil, typeKeyword) default: c, err := color.Parse(tok.value) if err == nil { d.expr.addValue(c, typeColor) } else { // TODO check for valid keywords d.expr.addValue(tok.value, typeKeyword) } } case tokenHash: c, err := color.Parse(tok.value) if err != nil { d.error(d.pos(tok), "%v, got %v", err, tok) } d.expr.addValue(c, typeColor) case tokenAtKeyword: d.expr.addValue(tok.value[1:], typeVar) case tokenURI: match := urlPath.FindStringSubmatch(tok.value) d.expr.addValue(match[1], typeURL) case tokenLBracket: // [field] tok = d.next() if tok.t != tokenIdent { d.error(d.pos(tok), "expected identifier in field name, got %v", tok) } d.expr.addValue("["+tok.value+"]", typeField) d.expect(tokenRBracket) case tokenFunction: d.expr.addValue(tok.value[:len(tok.value)-1], typeFunction) // strip lparen d.functionParams() case tokenLParen: d.exprPart() d.expect(tokenRParen) default: d.error(d.pos(tok), "unexpected value %v", tok) } }