Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0632664 authored by Cole Faust's avatar Cole Faust
Browse files

Move variable assignment handling to generation context

This allows the parsing code to be cleaner, as it
doesn't have to care about variable assignments.

Bug: 228518745
Test: go test
Change-Id: I33425c2fb51acab4901bfa82a53d337b75210f8e
parent 40f8c757
Loading
Loading
Loading
Loading
+4 −5
Original line number Original line Diff line number Diff line
@@ -233,18 +233,17 @@ func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlar


type variableRefExpr struct {
type variableRefExpr struct {
	ref variable
	ref variable
	isDefined bool
}
}


func NewVariableRefExpr(ref variable, isDefined bool) starlarkExpr {
func NewVariableRefExpr(ref variable) starlarkExpr {
	if predefined, ok := ref.(*predefinedVariable); ok {
	if predefined, ok := ref.(*predefinedVariable); ok {
		return predefined.value
		return predefined.value
	}
	}
	return &variableRefExpr{ref, isDefined}
	return &variableRefExpr{ref}
}
}


func (v *variableRefExpr) emit(gctx *generationContext) {
func (v *variableRefExpr) emit(gctx *generationContext) {
	v.ref.emitGet(gctx, v.isDefined)
	v.ref.emitGet(gctx)
}
}


func (v *variableRefExpr) typ() starlarkType {
func (v *variableRefExpr) typ() starlarkType {
+54 −54
Original line number Original line Diff line number Diff line
@@ -195,6 +195,14 @@ func isMakeControlFunc(s string) bool {
	return s == "error" || s == "warning" || s == "info"
	return s == "error" || s == "warning" || s == "info"
}
}


// varAssignmentScope points to the last assignment for each variable
// in the current block. It is used during the parsing to chain
// the assignments to a variable together.
type varAssignmentScope struct {
	outer *varAssignmentScope
	vars  map[string]bool
}

// Starlark output generation context
// Starlark output generation context
type generationContext struct {
type generationContext struct {
	buf            strings.Builder
	buf            strings.Builder
@@ -202,10 +210,42 @@ type generationContext struct {
	indentLevel    int
	indentLevel    int
	inAssignment   bool
	inAssignment   bool
	tracedCount    int
	tracedCount    int
	varAssignments *varAssignmentScope
}
}


func NewGenerateContext(ss *StarlarkScript) *generationContext {
func NewGenerateContext(ss *StarlarkScript) *generationContext {
	return &generationContext{starScript: ss}
	return &generationContext{
		starScript: ss,
		varAssignments: &varAssignmentScope{
			outer: nil,
			vars:  make(map[string]bool),
		},
	}
}

func (gctx *generationContext) pushVariableAssignments() {
	va := &varAssignmentScope{
		outer: gctx.varAssignments,
		vars:  make(map[string]bool),
	}
	gctx.varAssignments = va
}

func (gctx *generationContext) popVariableAssignments() {
	gctx.varAssignments = gctx.varAssignments.outer
}

func (gctx *generationContext) hasBeenAssigned(v variable) bool {
	for va := gctx.varAssignments; va != nil; va = va.outer {
		if _, ok := va.vars[v.name()]; ok {
			return true
		}
	}
	return false
}

func (gctx *generationContext) setHasBeenAssigned(v variable) {
	gctx.varAssignments.vars[v.name()] = true
}
}


// emit returns generated script
// emit returns generated script
@@ -392,14 +432,6 @@ type StarlarkScript struct {
	nodeLocator    func(pos mkparser.Pos) int
	nodeLocator    func(pos mkparser.Pos) int
}
}


// varAssignmentScope points to the last assignment for each variable
// in the current block. It is used during the parsing to chain
// the assignments to a variable together.
type varAssignmentScope struct {
	outer *varAssignmentScope
	vars  map[string]*assignmentNode
}

// parseContext holds the script we are generating and all the ephemeral data
// parseContext holds the script we are generating and all the ephemeral data
// needed during the parsing.
// needed during the parsing.
type parseContext struct {
type parseContext struct {
@@ -413,7 +445,6 @@ type parseContext struct {
	errorLogger      ErrorLogger
	errorLogger      ErrorLogger
	tracedVariables  map[string]bool // variables to be traced in the generated script
	tracedVariables  map[string]bool // variables to be traced in the generated script
	variables        map[string]variable
	variables        map[string]variable
	varAssignments   *varAssignmentScope
	outputDir        string
	outputDir        string
	dependentModules map[string]*moduleInfo
	dependentModules map[string]*moduleInfo
	soongNamespaces  map[string]map[string]bool
	soongNamespaces  map[string]map[string]bool
@@ -466,7 +497,6 @@ func newParseContext(ss *StarlarkScript, nodes []mkparser.Node) *parseContext {
		typeHints:        make(map[string]starlarkType),
		typeHints:        make(map[string]starlarkType),
		atTopOfMakefile:  true,
		atTopOfMakefile:  true,
	}
	}
	ctx.pushVarAssignments()
	for _, item := range predefined {
	for _, item := range predefined {
		ctx.variables[item.name] = &predefinedVariable{
		ctx.variables[item.name] = &predefinedVariable{
			baseVariable: baseVariable{nam: item.name, typ: starlarkTypeString},
			baseVariable: baseVariable{nam: item.name, typ: starlarkTypeString},
@@ -477,31 +507,6 @@ func newParseContext(ss *StarlarkScript, nodes []mkparser.Node) *parseContext {
	return ctx
	return ctx
}
}


func (ctx *parseContext) lastAssignment(v variable) *assignmentNode {
	for va := ctx.varAssignments; va != nil; va = va.outer {
		if v, ok := va.vars[v.name()]; ok {
			return v
		}
	}
	return nil
}

func (ctx *parseContext) setLastAssignment(v variable, asgn *assignmentNode) {
	ctx.varAssignments.vars[v.name()] = asgn
}

func (ctx *parseContext) pushVarAssignments() {
	va := &varAssignmentScope{
		outer: ctx.varAssignments,
		vars:  make(map[string]*assignmentNode),
	}
	ctx.varAssignments = va
}

func (ctx *parseContext) popVarAssignments() {
	ctx.varAssignments = ctx.varAssignments.outer
}

func (ctx *parseContext) hasNodes() bool {
func (ctx *parseContext) hasNodes() bool {
	return ctx.currentNodeIndex < len(ctx.nodes)
	return ctx.currentNodeIndex < len(ctx.nodes)
}
}
@@ -583,8 +588,6 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) []starlarkNode
		asgn.value = &toStringExpr{expr: asgn.value}
		asgn.value = &toStringExpr{expr: asgn.value}
	}
	}


	asgn.previous = ctx.lastAssignment(lhs)
	ctx.setLastAssignment(lhs, asgn)
	switch a.Type {
	switch a.Type {
	case "=", ":=":
	case "=", ":=":
		asgn.flavor = asgnSet
		asgn.flavor = asgnSet
@@ -939,11 +942,8 @@ func (ctx *parseContext) handleIfBlock(ifDirective *mkparser.Directive) starlark
func (ctx *parseContext) processBranch(check *mkparser.Directive) *switchCase {
func (ctx *parseContext) processBranch(check *mkparser.Directive) *switchCase {
	block := &switchCase{gate: ctx.parseCondition(check)}
	block := &switchCase{gate: ctx.parseCondition(check)}
	defer func() {
	defer func() {
		ctx.popVarAssignments()
		ctx.ifNestLevel--
		ctx.ifNestLevel--

	}()
	}()
	ctx.pushVarAssignments()
	ctx.ifNestLevel++
	ctx.ifNestLevel++


	for ctx.hasNodes() {
	for ctx.hasNodes() {
@@ -967,7 +967,7 @@ func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode
		if !check.Args.Const() {
		if !check.Args.Const() {
			return ctx.newBadNode(check, "ifdef variable ref too complex: %s", check.Args.Dump())
			return ctx.newBadNode(check, "ifdef variable ref too complex: %s", check.Args.Dump())
		}
		}
		v := NewVariableRefExpr(ctx.addVariable(check.Args.Strings[0]), false)
		v := NewVariableRefExpr(ctx.addVariable(check.Args.Strings[0]))
		if strings.HasSuffix(check.Name, "ndef") {
		if strings.HasSuffix(check.Name, "ndef") {
			v = &notExpr{v}
			v = &notExpr{v}
		}
		}
@@ -1280,12 +1280,12 @@ func (ctx *parseContext) parseReference(node mkparser.Node, ref *mkparser.MakeSt
				args: []starlarkExpr{
				args: []starlarkExpr{
					&stringLiteralExpr{literal: substParts[0]},
					&stringLiteralExpr{literal: substParts[0]},
					&stringLiteralExpr{literal: substParts[1]},
					&stringLiteralExpr{literal: substParts[1]},
					NewVariableRefExpr(v, ctx.lastAssignment(v) != nil),
					NewVariableRefExpr(v),
				},
				},
			}
			}
		}
		}
		if v := ctx.addVariable(refDump); v != nil {
		if v := ctx.addVariable(refDump); v != nil {
			return NewVariableRefExpr(v, ctx.lastAssignment(v) != nil)
			return NewVariableRefExpr(v)
		}
		}
		return ctx.newBadExpr(node, "unknown variable %s", refDump)
		return ctx.newBadExpr(node, "unknown variable %s", refDump)
	}
	}
@@ -1381,7 +1381,7 @@ func (p *isProductInListCallParser) parse(ctx *parseContext, node mkparser.Node,
		return ctx.newBadExpr(node, "is-product-in-list requires an argument")
		return ctx.newBadExpr(node, "is-product-in-list requires an argument")
	}
	}
	return &inExpr{
	return &inExpr{
		expr:  &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
		expr:  NewVariableRefExpr(ctx.addVariable("TARGET_PRODUCT")),
		list:  maybeConvertToStringList(ctx.parseMakeString(node, args)),
		list:  maybeConvertToStringList(ctx.parseMakeString(node, args)),
		isNot: false,
		isNot: false,
	}
	}
@@ -1394,8 +1394,8 @@ func (p *isVendorBoardPlatformCallParser) parse(ctx *parseContext, node mkparser
		return ctx.newBadExpr(node, "cannot handle non-constant argument to is-vendor-board-platform")
		return ctx.newBadExpr(node, "cannot handle non-constant argument to is-vendor-board-platform")
	}
	}
	return &inExpr{
	return &inExpr{
		expr:  &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
		expr:  NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM")),
		list:  &variableRefExpr{ctx.addVariable(args.Dump() + "_BOARD_PLATFORMS"), true},
		list:  NewVariableRefExpr(ctx.addVariable(args.Dump() + "_BOARD_PLATFORMS")),
		isNot: false,
		isNot: false,
	}
	}
}
}
@@ -1407,8 +1407,8 @@ func (p *isVendorBoardQcomCallParser) parse(ctx *parseContext, node mkparser.Nod
		return ctx.newBadExpr(node, "is-vendor-board-qcom does not accept any arguments")
		return ctx.newBadExpr(node, "is-vendor-board-qcom does not accept any arguments")
	}
	}
	return &inExpr{
	return &inExpr{
		expr:  &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
		expr:  NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM")),
		list:  &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
		list:  NewVariableRefExpr(ctx.addVariable("QCOM_BOARD_PLATFORMS")),
		isNot: false,
		isNot: false,
	}
	}
}
}
+2 −2
Original line number Original line Diff line number Diff line
@@ -626,7 +626,7 @@ def init(g, handle):
    pass
    pass
  elif not rblf.board_platform_is(g, "copper"):
  elif not rblf.board_platform_is(g, "copper"):
    pass
    pass
  elif g.get("TARGET_BOARD_PLATFORM", "") not in g["QCOM_BOARD_PLATFORMS"]:
  elif g.get("TARGET_BOARD_PLATFORM", "") not in g.get("QCOM_BOARD_PLATFORMS", ""):
    pass
    pass
  elif g["TARGET_PRODUCT"] in g.get("PLATFORM_LIST", []):
  elif g["TARGET_PRODUCT"] in g.get("PLATFORM_LIST", []):
    pass
    pass
@@ -649,7 +649,7 @@ def init(g, handle):
    pass
    pass
  elif not rblf.board_platform_is(g, "copper"):
  elif not rblf.board_platform_is(g, "copper"):
    pass
    pass
  elif g.get("TARGET_BOARD_PLATFORM", "") in g["QCOM_BOARD_PLATFORMS"]:
  elif g.get("TARGET_BOARD_PLATFORM", "") in g.get("QCOM_BOARD_PLATFORMS", ""):
    pass
    pass
`,
`,
	},
	},
+5 −2
Original line number Original line Diff line number Diff line
@@ -196,7 +196,6 @@ type assignmentNode struct {
	flavor   assignmentFlavor
	flavor   assignmentFlavor
	location ErrorLocation
	location ErrorLocation
	isTraced bool
	isTraced bool
	previous *assignmentNode
}
}


func (asgn *assignmentNode) emit(gctx *generationContext) {
func (asgn *assignmentNode) emit(gctx *generationContext) {
@@ -209,7 +208,7 @@ func (asgn *assignmentNode) emit(gctx *generationContext) {
		gctx.newLine()
		gctx.newLine()
		gctx.tracedCount++
		gctx.tracedCount++
		gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
		gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
		asgn.lhs.emitGet(gctx, true)
		asgn.lhs.emitGet(gctx)
		gctx.writef(")")
		gctx.writef(")")
	}
	}
}
}
@@ -271,6 +270,7 @@ type switchCase struct {
func (cb *switchCase) emit(gctx *generationContext) {
func (cb *switchCase) emit(gctx *generationContext) {
	cb.gate.emit(gctx)
	cb.gate.emit(gctx)
	gctx.indentLevel++
	gctx.indentLevel++
	gctx.pushVariableAssignments()
	hasStatements := false
	hasStatements := false
	for _, node := range cb.nodes {
	for _, node := range cb.nodes {
		if _, ok := node.(*commentNode); !ok {
		if _, ok := node.(*commentNode); !ok {
@@ -282,6 +282,7 @@ func (cb *switchCase) emit(gctx *generationContext) {
		gctx.emitPass()
		gctx.emitPass()
	}
	}
	gctx.indentLevel--
	gctx.indentLevel--
	gctx.popVariableAssignments()
}
}


// A single complete if ... elseif ... else ... endif sequences
// A single complete if ... elseif ... else ... endif sequences
@@ -302,6 +303,7 @@ type foreachNode struct {
}
}


func (f *foreachNode) emit(gctx *generationContext) {
func (f *foreachNode) emit(gctx *generationContext) {
	gctx.pushVariableAssignments()
	gctx.newLine()
	gctx.newLine()
	gctx.writef("for %s in ", f.varName)
	gctx.writef("for %s in ", f.varName)
	f.list.emit(gctx)
	f.list.emit(gctx)
@@ -318,4 +320,5 @@ func (f *foreachNode) emit(gctx *generationContext) {
		gctx.emitPass()
		gctx.emitPass()
	}
	}
	gctx.indentLevel--
	gctx.indentLevel--
	gctx.popVariableAssignments()
}
}
+18 −36
Original line number Original line Diff line number Diff line
@@ -21,9 +21,8 @@ import (


type variable interface {
type variable interface {
	name() string
	name() string
	emitGet(gctx *generationContext, isDefined bool)
	emitGet(gctx *generationContext)
	emitSet(gctx *generationContext, asgn *assignmentNode)
	emitSet(gctx *generationContext, asgn *assignmentNode)
	emitDefined(gctx *generationContext)
	valueType() starlarkType
	valueType() starlarkType
	setValueType(t starlarkType)
	setValueType(t starlarkType)
	defaultValueString() string
	defaultValueString() string
@@ -74,13 +73,11 @@ type productConfigVariable struct {


func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
	emitAssignment := func() {
	emitAssignment := func() {
		pcv.emitGet(gctx, true)
		gctx.writef("cfg[%q] = ", pcv.nam)
		gctx.write(" = ")
		asgn.value.emitListVarCopy(gctx)
		asgn.value.emitListVarCopy(gctx)
	}
	}
	emitAppend := func() {
	emitAppend := func() {
		pcv.emitGet(gctx, true)
		gctx.writef("cfg[%q] += ", pcv.nam)
		gctx.write(" += ")
		value := asgn.value
		value := asgn.value
		if pcv.valueType() == starlarkTypeString {
		if pcv.valueType() == starlarkTypeString {
			gctx.writef(`" " + `)
			gctx.writef(`" " + `)
@@ -98,7 +95,7 @@ func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignme
	}
	}


	// If we are not sure variable has been assigned before, emit setdefault
	// If we are not sure variable has been assigned before, emit setdefault
	needsSetDefault := asgn.previous == nil && !pcv.isPreset() && asgn.isSelfReferential()
	needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential()


	switch asgn.flavor {
	switch asgn.flavor {
	case asgnSet:
	case asgnSet:
@@ -121,34 +118,30 @@ func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignme
		emitAssignment()
		emitAssignment()
		gctx.indentLevel--
		gctx.indentLevel--
	}
	}

	gctx.setHasBeenAssigned(&pcv)
}
}


func (pcv productConfigVariable) emitGet(gctx *generationContext, isDefined bool) {
func (pcv productConfigVariable) emitGet(gctx *generationContext) {
	if isDefined || pcv.isPreset() {
	if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
		gctx.writef("cfg[%q]", pcv.nam)
		gctx.writef("cfg[%q]", pcv.nam)
	} else {
	} else {
		gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
		gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
	}
	}
}
}


func (pcv productConfigVariable) emitDefined(gctx *generationContext) {
	gctx.writef("cfg.get(%q) != None", pcv.name())
}

type otherGlobalVariable struct {
type otherGlobalVariable struct {
	baseVariable
	baseVariable
}
}


func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
	emitAssignment := func() {
	emitAssignment := func() {
		scv.emitGet(gctx, true)
		gctx.writef("g[%q] = ", scv.nam)
		gctx.write(" = ")
		asgn.value.emitListVarCopy(gctx)
		asgn.value.emitListVarCopy(gctx)
	}
	}


	emitAppend := func() {
	emitAppend := func() {
		scv.emitGet(gctx, true)
		gctx.writef("g[%q] += ", scv.nam)
		gctx.write(" += ")
		value := asgn.value
		value := asgn.value
		if scv.valueType() == starlarkTypeString {
		if scv.valueType() == starlarkTypeString {
			gctx.writef(`" " + `)
			gctx.writef(`" " + `)
@@ -158,7 +151,7 @@ func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignment
	}
	}


	// If we are not sure variable has been assigned before, emit setdefault
	// If we are not sure variable has been assigned before, emit setdefault
	needsSetDefault := asgn.previous == nil && !scv.isPreset() && asgn.isSelfReferential()
	needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()


	switch asgn.flavor {
	switch asgn.flavor {
	case asgnSet:
	case asgnSet:
@@ -184,28 +177,22 @@ func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignment
		emitAssignment()
		emitAssignment()
		gctx.indentLevel--
		gctx.indentLevel--
	}
	}

	gctx.setHasBeenAssigned(&scv)
}
}


func (scv otherGlobalVariable) emitGet(gctx *generationContext, isDefined bool) {
func (scv otherGlobalVariable) emitGet(gctx *generationContext) {
	if isDefined || scv.isPreset() {
	if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
		gctx.writef("g[%q]", scv.nam)
		gctx.writef("g[%q]", scv.nam)
	} else {
	} else {
		gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
		gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
	}
	}
}
}


func (scv otherGlobalVariable) emitDefined(gctx *generationContext) {
	gctx.writef("g.get(%q) != None", scv.name())
}

type localVariable struct {
type localVariable struct {
	baseVariable
	baseVariable
}
}


func (lv localVariable) emitDefined(gctx *generationContext) {
	gctx.writef(lv.String())
}

func (lv localVariable) String() string {
func (lv localVariable) String() string {
	return "_" + lv.nam
	return "_" + lv.nam
}
}
@@ -216,8 +203,7 @@ func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
		gctx.writef("%s = ", lv)
		gctx.writef("%s = ", lv)
		asgn.value.emitListVarCopy(gctx)
		asgn.value.emitListVarCopy(gctx)
	case asgnAppend:
	case asgnAppend:
		lv.emitGet(gctx, false)
		gctx.writef("%s += ", lv)
		gctx.write(" += ")
		value := asgn.value
		value := asgn.value
		if lv.valueType() == starlarkTypeString {
		if lv.valueType() == starlarkTypeString {
			gctx.writef(`" " + `)
			gctx.writef(`" " + `)
@@ -227,7 +213,7 @@ func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
	}
	}
}
}


func (lv localVariable) emitGet(gctx *generationContext, _ bool) {
func (lv localVariable) emitGet(gctx *generationContext) {
	gctx.writef("%s", lv)
	gctx.writef("%s", lv)
}
}


@@ -236,7 +222,7 @@ type predefinedVariable struct {
	value starlarkExpr
	value starlarkExpr
}
}


func (pv predefinedVariable) emitGet(gctx *generationContext, _ bool) {
func (pv predefinedVariable) emitGet(gctx *generationContext) {
	pv.value.emit(gctx)
	pv.value.emit(gctx)
}
}


@@ -257,10 +243,6 @@ func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNo
	panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
	panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
}
}


func (pv predefinedVariable) emitDefined(gctx *generationContext) {
	gctx.write("True")
}

var localProductConfigVariables = map[string]string{
var localProductConfigVariables = map[string]string{
	"LOCAL_AUDIO_PRODUCT_PACKAGE":         "PRODUCT_PACKAGES",
	"LOCAL_AUDIO_PRODUCT_PACKAGE":         "PRODUCT_PACKAGES",
	"LOCAL_AUDIO_PRODUCT_COPY_FILES":      "PRODUCT_COPY_FILES",
	"LOCAL_AUDIO_PRODUCT_COPY_FILES":      "PRODUCT_COPY_FILES",