Home | History | Annotate | Download | only in kati
      1 // Copyright 2015 Google Inc. All rights reserved
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package kati
     16 
     17 import (
     18 	"strings"
     19 
     20 	"github.com/golang/glog"
     21 )
     22 
     23 type ast interface {
     24 	eval(*Evaluator) error
     25 	show()
     26 }
     27 
     28 type assignAST struct {
     29 	srcpos
     30 	lhs Value
     31 	rhs Value
     32 	op  string
     33 	opt string // "override", "export"
     34 }
     35 
     36 func (ast *assignAST) eval(ev *Evaluator) error {
     37 	return ev.evalAssign(ast)
     38 }
     39 
     40 func (ast *assignAST) evalRHS(ev *Evaluator, lhs string) (Var, error) {
     41 	origin := "file"
     42 	if ast.filename == bootstrapMakefileName {
     43 		origin = "default"
     44 	}
     45 	if ast.opt == "override" {
     46 		origin = "override"
     47 	}
     48 	// TODO(ukai): handle ast.opt == "export"
     49 	switch ast.op {
     50 	case ":=":
     51 		switch v := ast.rhs.(type) {
     52 		case literal:
     53 			return &simpleVar{value: []string{v.String()}, origin: origin}, nil
     54 		case tmpval:
     55 			return &simpleVar{value: []string{v.String()}, origin: origin}, nil
     56 		default:
     57 			var buf evalBuffer
     58 			buf.resetSep()
     59 			err := v.Eval(&buf, ev)
     60 			if err != nil {
     61 				return nil, err
     62 			}
     63 			return &simpleVar{value: []string{buf.String()}, origin: origin}, nil
     64 		}
     65 	case "=":
     66 		return &recursiveVar{expr: ast.rhs, origin: origin}, nil
     67 	case "+=":
     68 		prev := ev.lookupVarInCurrentScope(lhs)
     69 		if !prev.IsDefined() {
     70 			return &recursiveVar{expr: ast.rhs, origin: origin}, nil
     71 		}
     72 		return prev.AppendVar(ev, ast.rhs)
     73 	case "?=":
     74 		prev := ev.lookupVarInCurrentScope(lhs)
     75 		if prev.IsDefined() {
     76 			return prev, nil
     77 		}
     78 		return &recursiveVar{expr: ast.rhs, origin: origin}, nil
     79 	}
     80 	return nil, ast.errorf("unknown assign op: %q", ast.op)
     81 }
     82 
     83 func (ast *assignAST) show() {
     84 	glog.Infof("%s %s %s %q", ast.opt, ast.lhs, ast.op, ast.rhs)
     85 }
     86 
     87 // maybeRuleAST is an ast for rule line.
     88 // Note we cannot be sure what this is, until all variables in |expr|
     89 // are expanded.
     90 type maybeRuleAST struct {
     91 	srcpos
     92 	isRule bool // found literal ':'
     93 	expr   Value
     94 	assign *assignAST // target specific var
     95 	semi   []byte     // after ';' if ';' exists
     96 }
     97 
     98 func (ast *maybeRuleAST) eval(ev *Evaluator) error {
     99 	return ev.evalMaybeRule(ast)
    100 }
    101 
    102 func (ast *maybeRuleAST) show() {
    103 	glog.Info(ast.expr)
    104 }
    105 
    106 type commandAST struct {
    107 	srcpos
    108 	cmd string
    109 }
    110 
    111 func (ast *commandAST) eval(ev *Evaluator) error {
    112 	return ev.evalCommand(ast)
    113 }
    114 
    115 func (ast *commandAST) show() {
    116 	glog.Infof("\t%s", strings.Replace(ast.cmd, "\n", `\n`, -1))
    117 }
    118 
    119 type includeAST struct {
    120 	srcpos
    121 	expr string
    122 	op   string
    123 }
    124 
    125 func (ast *includeAST) eval(ev *Evaluator) error {
    126 	return ev.evalInclude(ast)
    127 }
    128 
    129 func (ast *includeAST) show() {
    130 	glog.Infof("include %s", ast.expr)
    131 }
    132 
    133 type ifAST struct {
    134 	srcpos
    135 	op         string
    136 	lhs        Value
    137 	rhs        Value // Empty if |op| is ifdef or ifndef.
    138 	trueStmts  []ast
    139 	falseStmts []ast
    140 }
    141 
    142 func (ast *ifAST) eval(ev *Evaluator) error {
    143 	return ev.evalIf(ast)
    144 }
    145 
    146 func (ast *ifAST) show() {
    147 	// TODO
    148 	glog.Info("if")
    149 }
    150 
    151 type exportAST struct {
    152 	srcpos
    153 	expr     []byte
    154 	hasEqual bool
    155 	export   bool
    156 }
    157 
    158 func (ast *exportAST) eval(ev *Evaluator) error {
    159 	return ev.evalExport(ast)
    160 }
    161 
    162 func (ast *exportAST) show() {
    163 	// TODO
    164 	glog.Info("export")
    165 }
    166 
    167 type vpathAST struct {
    168 	srcpos
    169 	expr Value
    170 }
    171 
    172 func (ast *vpathAST) eval(ev *Evaluator) error {
    173 	return ev.evalVpath(ast)
    174 }
    175 
    176 func (ast *vpathAST) show() {
    177 	glog.Infof("vpath %s", ast.expr.String())
    178 }
    179