Add soong_build primary builder
Initial build logic for building android with soong. It can build a variety of C and C++ files for arm/arm64 and host. Change-Id: I10eb37c2c2a50be6af1bb5fd568c0962b9476bf0
This commit is contained in:
115
androidmk/cmd/androidmk/android.go
Normal file
115
androidmk/cmd/androidmk/android.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"android/soong/androidmk/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
clear_vars = "__android_mk_clear_vars"
|
||||
build_shared_library = "cc_library_shared"
|
||||
build_static_library = "cc_library_static"
|
||||
build_host_static_library = "cc_library_host_static"
|
||||
build_host_shared_library = "cc_library_host_shared"
|
||||
build_executable = "cc_binary"
|
||||
build_host_executable = "cc_binary_host"
|
||||
build_native_test = "cc_test"
|
||||
build_prebuilt = "prebuilt"
|
||||
)
|
||||
|
||||
var stringProperties = map[string]string{
|
||||
"LOCAL_MODULE": "name",
|
||||
"LOCAL_MODULE_STEM": "stem",
|
||||
"LOCAL_MODULE_CLASS": "class",
|
||||
"LOCAL_CXX_STL": "cxx_stl",
|
||||
"LOCAL_STRIP_MODULE": "strip",
|
||||
"LOCAL_MULTILIB": "compile_multilib",
|
||||
}
|
||||
|
||||
var listProperties = map[string]string{
|
||||
"LOCAL_SRC_FILES": "srcs",
|
||||
"LOCAL_SHARED_LIBRARIES": "shared_libs",
|
||||
"LOCAL_STATIC_LIBRARIES": "static_libs",
|
||||
"LOCAL_WHOLE_STATIC_LIBRARIES": "whole_static_libs",
|
||||
"LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs",
|
||||
"LOCAL_C_INCLUDES": "include_dirs",
|
||||
"LOCAL_EXPORT_C_INCLUDE_DIRS": "export_include_dirs",
|
||||
"LOCAL_ASFLAGS": "asflags",
|
||||
"LOCAL_CLANG_ASFLAGS": "clang_asflags",
|
||||
"LOCAL_CFLAGS": "cflags",
|
||||
"LOCAL_CONLYFLAGS": "conlyflags",
|
||||
"LOCAL_CPPFLAGS": "cppflags",
|
||||
"LOCAL_LDFLAGS": "ldflags",
|
||||
"LOCAL_REQUIRED_MODULES": "required",
|
||||
"LOCAL_MODULE_TAGS": "tags",
|
||||
"LOCAL_LDLIBS": "host_ldlibs",
|
||||
"LOCAL_CLANG_CFLAGS": "clang_cflags",
|
||||
}
|
||||
|
||||
var boolProperties = map[string]string{
|
||||
"LOCAL_IS_HOST_MODULE": "host",
|
||||
"LOCAL_CLANG": "clang",
|
||||
"LOCAL_FORCE_STATIC_EXECUTABLE": "static",
|
||||
"LOCAL_ADDRESS_SANITIZER": "asan",
|
||||
"LOCAL_NATIVE_COVERAGE": "native_coverage",
|
||||
"LOCAL_NO_CRT": "nocrt",
|
||||
"LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols",
|
||||
"LOCAL_RTTI_FLAG": "rtti",
|
||||
}
|
||||
|
||||
var propertySuffixes = []struct {
|
||||
suffix string
|
||||
class string
|
||||
}{
|
||||
{"arm", "arch"},
|
||||
{"arm64", "arch"},
|
||||
{"mips", "arch"},
|
||||
{"mips64", "arch"},
|
||||
{"x86", "arch"},
|
||||
{"x86_64", "arch"},
|
||||
{"32", "multilib"},
|
||||
{"64", "multilib"},
|
||||
}
|
||||
|
||||
var propertySuffixTranslations = map[string]string{
|
||||
"32": "lib32",
|
||||
"64": "lib64",
|
||||
}
|
||||
|
||||
var conditionalTranslations = map[string]struct {
|
||||
class string
|
||||
suffix string
|
||||
}{
|
||||
"($(HOST_OS),darwin)": {"host_os", "darwin"},
|
||||
"($(HOST_OS), darwin)": {"host_os", "darwin"},
|
||||
"($(HOST_OS),windows)": {"host_os", "windows"},
|
||||
"($(HOST_OS), windows)": {"host_os", "windows"},
|
||||
}
|
||||
|
||||
func mydir(args []string) string {
|
||||
return "."
|
||||
}
|
||||
|
||||
func androidScope() parser.Scope {
|
||||
globalScope := parser.NewScope(nil)
|
||||
globalScope.Set("CLEAR_VARS", clear_vars)
|
||||
globalScope.Set("BUILD_HOST_EXECUTABLE", build_host_executable)
|
||||
globalScope.Set("BUILD_SHARED_LIBRARY", build_shared_library)
|
||||
globalScope.Set("BUILD_STATIC_LIBRARY", build_static_library)
|
||||
globalScope.Set("BUILD_HOST_STATIC_LIBRARY", build_host_static_library)
|
||||
globalScope.Set("BUILD_HOST_SHARED_LIBRARY", build_host_shared_library)
|
||||
globalScope.Set("BUILD_NATIVE_TEST", build_native_test)
|
||||
globalScope.Set("BUILD_EXECUTABLE", build_executable)
|
||||
globalScope.Set("BUILD_PREBUILT", build_prebuilt)
|
||||
globalScope.SetFunc("my-dir", mydir)
|
||||
|
||||
globalScope.Set("lib32", "lib32")
|
||||
globalScope.Set("lib64", "lib64")
|
||||
globalScope.Set("arm", "arm")
|
||||
globalScope.Set("arm64", "arm64")
|
||||
globalScope.Set("mips", "mips")
|
||||
globalScope.Set("mips64", "mips64")
|
||||
globalScope.Set("x86", "x86")
|
||||
globalScope.Set("x86_64", "x86_64")
|
||||
|
||||
return globalScope
|
||||
}
|
438
androidmk/cmd/androidmk/androidmk.go
Normal file
438
androidmk/cmd/androidmk/androidmk.go
Normal file
@@ -0,0 +1,438 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
|
||||
mkparser "android/soong/androidmk/parser"
|
||||
|
||||
bpparser "blueprint/parser"
|
||||
)
|
||||
|
||||
// TODO: non-expanded variables with expressions
|
||||
|
||||
type bpFile struct {
|
||||
comments []bpparser.Comment
|
||||
defs []bpparser.Definition
|
||||
localAssignments map[string]*bpparser.Property
|
||||
globalAssignments map[string]*bpparser.Value
|
||||
scope mkparser.Scope
|
||||
module *bpparser.Module
|
||||
|
||||
pos scanner.Position
|
||||
prevLine, line int
|
||||
}
|
||||
|
||||
func (f *bpFile) errorf(thing mkparser.MakeThing, s string, args ...interface{}) {
|
||||
orig := thing.Dump()
|
||||
s = fmt.Sprintf(s, args...)
|
||||
f.comments = append(f.comments, bpparser.Comment{
|
||||
Comment: fmt.Sprintf("// ANDROIDMK TRANSLATION ERROR: %s", s),
|
||||
Pos: f.pos,
|
||||
})
|
||||
lines := strings.Split(orig, "\n")
|
||||
for _, l := range lines {
|
||||
f.incPos()
|
||||
f.comments = append(f.comments, bpparser.Comment{
|
||||
Comment: "// " + l,
|
||||
Pos: f.pos,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *bpFile) setPos(pos, endPos scanner.Position) {
|
||||
f.pos = pos
|
||||
|
||||
f.line++
|
||||
if f.pos.Line > f.prevLine+1 {
|
||||
f.line++
|
||||
}
|
||||
|
||||
f.pos.Line = f.line
|
||||
f.prevLine = endPos.Line
|
||||
}
|
||||
|
||||
func (f *bpFile) incPos() {
|
||||
f.pos.Line++
|
||||
f.line++
|
||||
f.prevLine++
|
||||
}
|
||||
|
||||
type conditional struct {
|
||||
cond string
|
||||
eq bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
b, err := ioutil.ReadFile(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
p := mkparser.NewParser(os.Args[1], bytes.NewBuffer(b))
|
||||
|
||||
things, errs := p.Parse()
|
||||
if len(errs) > 0 {
|
||||
for _, err := range errs {
|
||||
fmt.Println("ERROR: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
file := &bpFile{
|
||||
scope: androidScope(),
|
||||
localAssignments: make(map[string]*bpparser.Property),
|
||||
globalAssignments: make(map[string]*bpparser.Value),
|
||||
}
|
||||
|
||||
var conds []*conditional
|
||||
var cond *conditional
|
||||
|
||||
for _, t := range things {
|
||||
file.setPos(t.Pos(), t.EndPos())
|
||||
|
||||
if comment, ok := t.AsComment(); ok {
|
||||
file.comments = append(file.comments, bpparser.Comment{
|
||||
Pos: file.pos,
|
||||
Comment: "//" + comment.Comment,
|
||||
})
|
||||
} else if assignment, ok := t.AsAssignment(); ok {
|
||||
handleAssignment(file, assignment, cond)
|
||||
} else if directive, ok := t.AsDirective(); ok {
|
||||
switch directive.Name {
|
||||
case "include":
|
||||
val := directive.Args.Value(file.scope)
|
||||
switch val {
|
||||
case build_shared_library, build_static_library,
|
||||
build_executable, build_host_executable,
|
||||
build_prebuilt, build_host_static_library,
|
||||
build_host_shared_library, build_native_test:
|
||||
|
||||
handleModuleConditionals(file, directive, cond)
|
||||
makeModule(file, val)
|
||||
case clear_vars:
|
||||
resetModule(file)
|
||||
default:
|
||||
file.errorf(directive, "unsupported include")
|
||||
continue
|
||||
}
|
||||
case "ifeq", "ifneq":
|
||||
args := directive.Args.Dump()
|
||||
eq := directive.Name == "ifeq"
|
||||
switch args {
|
||||
case "($(HOST_OS),windows)", "($(HOST_OS), windows)",
|
||||
"($(HOST_OS),darwin)", "($(HOST_OS), darwin)":
|
||||
newCond := conditional{args, eq}
|
||||
conds = append(conds, &newCond)
|
||||
if cond == nil {
|
||||
cond = &newCond
|
||||
} else {
|
||||
file.errorf(directive, "unsupported nested conditional")
|
||||
}
|
||||
default:
|
||||
file.errorf(directive, "unsupported conditional")
|
||||
conds = append(conds, nil)
|
||||
continue
|
||||
}
|
||||
case "else":
|
||||
if len(conds) == 0 {
|
||||
file.errorf(directive, "missing if before else")
|
||||
continue
|
||||
} else if conds[len(conds)-1] == nil {
|
||||
file.errorf(directive, "else from unsupported contitional")
|
||||
continue
|
||||
}
|
||||
cond.eq = !cond.eq
|
||||
case "endif":
|
||||
if len(conds) == 0 {
|
||||
file.errorf(directive, "missing if before endif")
|
||||
continue
|
||||
} else if conds[len(conds)-1] == nil {
|
||||
file.errorf(directive, "endif from unsupported contitional")
|
||||
conds = conds[:len(conds)-1]
|
||||
} else {
|
||||
if cond == conds[len(conds)-1] {
|
||||
cond = nil
|
||||
}
|
||||
conds = conds[:len(conds)-1]
|
||||
}
|
||||
default:
|
||||
file.errorf(directive, "unsupported directive")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out, err := bpparser.Print(&bpparser.File{
|
||||
Defs: file.defs,
|
||||
Comments: file.comments,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Print(string(out))
|
||||
}
|
||||
|
||||
func handleAssignment(file *bpFile, assignment mkparser.Assignment, c *conditional) {
|
||||
if !assignment.Name.Const() {
|
||||
file.errorf(assignment, "unsupported non-const variable name")
|
||||
return
|
||||
}
|
||||
|
||||
if assignment.Target != nil {
|
||||
file.errorf(assignment, "unsupported target assignment")
|
||||
return
|
||||
}
|
||||
|
||||
name := assignment.Name.Value(nil)
|
||||
suffix := ""
|
||||
class := ""
|
||||
|
||||
if strings.HasPrefix(name, "LOCAL_") {
|
||||
for _, v := range propertySuffixes {
|
||||
s, c := v.suffix, v.class
|
||||
if strings.HasSuffix(name, "_"+s) {
|
||||
name = strings.TrimSuffix(name, "_"+s)
|
||||
suffix = s
|
||||
if s, ok := propertySuffixTranslations[s]; ok {
|
||||
suffix = s
|
||||
}
|
||||
class = c
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
if class != "" {
|
||||
file.errorf(assignment, "suffix assignment inside conditional, skipping conditional")
|
||||
} else {
|
||||
if v, ok := conditionalTranslations[c.cond]; ok {
|
||||
class = v.class
|
||||
suffix = v.suffix
|
||||
if !c.eq {
|
||||
suffix = "not_" + suffix
|
||||
}
|
||||
} else {
|
||||
panic("unknown conditional")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if c != nil {
|
||||
eq := "eq"
|
||||
if !c.eq {
|
||||
eq = "neq"
|
||||
}
|
||||
file.errorf(assignment, "conditional %s %s on global assignment", eq, c.cond)
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if prop, ok := stringProperties[name]; ok {
|
||||
err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.String, true, class, suffix)
|
||||
} else if prop, ok := listProperties[name]; ok {
|
||||
err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.List, true, class, suffix)
|
||||
} else if prop, ok := boolProperties[name]; ok {
|
||||
err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.Bool, true, class, suffix)
|
||||
} else {
|
||||
if name == "LOCAL_PATH" {
|
||||
// Nothing to do, except maybe avoid the "./" in paths?
|
||||
} else if strings.HasPrefix(name, "LOCAL_") {
|
||||
//setVariable(file, assignment, name, bpparser.String, true)
|
||||
switch name {
|
||||
case "LOCAL_ADDITIONAL_DEPENDENCIES":
|
||||
// TODO: check for only .mk files?
|
||||
default:
|
||||
file.errorf(assignment, "unsupported assignment to %s", name)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = setVariable(file, assignment.Value, assignment.Type == "+=", name, bpparser.List, false, class, suffix)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
file.errorf(assignment, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func handleModuleConditionals(file *bpFile, directive mkparser.Directive, c *conditional) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if v, ok := conditionalTranslations[c.cond]; ok {
|
||||
class := v.class
|
||||
suffix := v.suffix
|
||||
disabledSuffix := v.suffix
|
||||
if !c.eq {
|
||||
suffix = "not_" + suffix
|
||||
} else {
|
||||
disabledSuffix = "not_" + disabledSuffix
|
||||
}
|
||||
|
||||
// Hoist all properties inside the condtional up to the top level
|
||||
file.module.Properties = file.localAssignments[class+"___"+suffix].Value.MapValue
|
||||
file.module.Properties = append(file.module.Properties, file.localAssignments[class])
|
||||
file.localAssignments[class+"___"+suffix].Value.MapValue = nil
|
||||
for i := range file.localAssignments[class].Value.MapValue {
|
||||
if file.localAssignments[class].Value.MapValue[i].Name.Name == suffix {
|
||||
file.localAssignments[class].Value.MapValue =
|
||||
append(file.localAssignments[class].Value.MapValue[:i],
|
||||
file.localAssignments[class].Value.MapValue[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a fake assignment with enabled = false
|
||||
err := setVariable(file, mkparser.SimpleMakeString("true", file.pos), false,
|
||||
"disabled", bpparser.Bool, true, class, disabledSuffix)
|
||||
if err != nil {
|
||||
file.errorf(directive, err.Error())
|
||||
}
|
||||
} else {
|
||||
panic("unknown conditional")
|
||||
}
|
||||
}
|
||||
|
||||
func makeModule(file *bpFile, t string) {
|
||||
file.module.Type = bpparser.Ident{
|
||||
Name: t,
|
||||
Pos: file.module.LbracePos,
|
||||
}
|
||||
file.module.RbracePos = file.pos
|
||||
file.defs = append(file.defs, file.module)
|
||||
}
|
||||
|
||||
func resetModule(file *bpFile) {
|
||||
file.module = &bpparser.Module{}
|
||||
file.module.LbracePos = file.pos
|
||||
file.localAssignments = make(map[string]*bpparser.Property)
|
||||
}
|
||||
|
||||
func setVariable(file *bpFile, val *mkparser.MakeString, plusequals bool, name string,
|
||||
typ bpparser.ValueType, local bool, class string, suffix string) error {
|
||||
|
||||
pos := file.pos
|
||||
|
||||
var oldValue *bpparser.Value
|
||||
if local {
|
||||
var oldProp *bpparser.Property
|
||||
if class != "" {
|
||||
oldProp = file.localAssignments[name+"___"+class+"___"+suffix]
|
||||
} else {
|
||||
oldProp = file.localAssignments[name]
|
||||
}
|
||||
if oldProp != nil {
|
||||
oldValue = &oldProp.Value
|
||||
}
|
||||
} else {
|
||||
oldValue = file.globalAssignments[name]
|
||||
}
|
||||
|
||||
var exp *bpparser.Value
|
||||
var err error
|
||||
switch typ {
|
||||
case bpparser.List:
|
||||
exp, err = makeToListExpression(val)
|
||||
case bpparser.String:
|
||||
exp, err = makeToStringExpression(val)
|
||||
case bpparser.Bool:
|
||||
exp, err = makeToBoolExpression(val)
|
||||
default:
|
||||
panic("unknown type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if local {
|
||||
if oldValue != nil && plusequals {
|
||||
val, err := addValues(oldValue, exp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unsupported addition: %s", err.Error())
|
||||
}
|
||||
val.Expression.Pos = pos
|
||||
*oldValue = *val
|
||||
} else if class == "" {
|
||||
prop := &bpparser.Property{
|
||||
Name: bpparser.Ident{Name: name, Pos: pos},
|
||||
Pos: pos,
|
||||
Value: *exp,
|
||||
}
|
||||
file.localAssignments[name] = prop
|
||||
file.module.Properties = append(file.module.Properties, prop)
|
||||
} else {
|
||||
classProp := file.localAssignments[class]
|
||||
if classProp == nil {
|
||||
classProp = &bpparser.Property{
|
||||
Name: bpparser.Ident{Name: class, Pos: pos},
|
||||
Pos: pos,
|
||||
Value: bpparser.Value{
|
||||
Type: bpparser.Map,
|
||||
MapValue: []*bpparser.Property{},
|
||||
},
|
||||
}
|
||||
file.localAssignments[class] = classProp
|
||||
file.module.Properties = append(file.module.Properties, classProp)
|
||||
}
|
||||
|
||||
suffixProp := file.localAssignments[class+"___"+suffix]
|
||||
if suffixProp == nil {
|
||||
suffixProp = &bpparser.Property{
|
||||
Name: bpparser.Ident{Name: suffix, Pos: pos},
|
||||
Pos: pos,
|
||||
Value: bpparser.Value{
|
||||
Type: bpparser.Map,
|
||||
MapValue: []*bpparser.Property{},
|
||||
},
|
||||
}
|
||||
file.localAssignments[class+"___"+suffix] = suffixProp
|
||||
classProp.Value.MapValue = append(classProp.Value.MapValue, suffixProp)
|
||||
}
|
||||
|
||||
prop := &bpparser.Property{
|
||||
Name: bpparser.Ident{Name: name, Pos: pos},
|
||||
Pos: pos,
|
||||
Value: *exp,
|
||||
}
|
||||
file.localAssignments[class+"___"+suffix+"___"+name] = prop
|
||||
suffixProp.Value.MapValue = append(suffixProp.Value.MapValue, prop)
|
||||
}
|
||||
} else {
|
||||
if oldValue != nil && plusequals {
|
||||
a := &bpparser.Assignment{
|
||||
Name: bpparser.Ident{
|
||||
Name: name,
|
||||
Pos: pos,
|
||||
},
|
||||
Value: *exp,
|
||||
OrigValue: *exp,
|
||||
Pos: pos,
|
||||
Assigner: "+=",
|
||||
}
|
||||
file.defs = append(file.defs, a)
|
||||
} else {
|
||||
a := &bpparser.Assignment{
|
||||
Name: bpparser.Ident{
|
||||
Name: name,
|
||||
Pos: pos,
|
||||
},
|
||||
Value: *exp,
|
||||
OrigValue: *exp,
|
||||
Pos: pos,
|
||||
Assigner: "=",
|
||||
}
|
||||
file.globalAssignments[name] = &a.Value
|
||||
file.defs = append(file.defs, a)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
192
androidmk/cmd/androidmk/values.go
Normal file
192
androidmk/cmd/androidmk/values.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
mkparser "android/soong/androidmk/parser"
|
||||
|
||||
bpparser "blueprint/parser"
|
||||
)
|
||||
|
||||
func stringToStringValue(s string) *bpparser.Value {
|
||||
return &bpparser.Value{
|
||||
Type: bpparser.String,
|
||||
StringValue: s,
|
||||
}
|
||||
}
|
||||
|
||||
func addValues(val1, val2 *bpparser.Value) (*bpparser.Value, error) {
|
||||
if val1.Type == bpparser.String && val2.Type == bpparser.List {
|
||||
val1 = &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
ListValue: []bpparser.Value{*val1},
|
||||
}
|
||||
} else if val2.Type == bpparser.String && val1.Type == bpparser.List {
|
||||
val2 = &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
ListValue: []bpparser.Value{*val1},
|
||||
}
|
||||
} else if val1.Type != val2.Type {
|
||||
return nil, fmt.Errorf("cannot add mismatched types")
|
||||
}
|
||||
|
||||
return &bpparser.Value{
|
||||
Type: val1.Type,
|
||||
Expression: &bpparser.Expression{
|
||||
Operator: '+',
|
||||
Args: [2]bpparser.Value{*val1, *val2},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeToStringExpression(ms *mkparser.MakeString) (*bpparser.Value, error) {
|
||||
var val *bpparser.Value
|
||||
var err error
|
||||
|
||||
if ms.Strings[0] != "" {
|
||||
val = stringToStringValue(ms.Strings[0])
|
||||
}
|
||||
|
||||
for i, s := range ms.Strings[1:] {
|
||||
name := ms.Variables[i].Name
|
||||
if !name.Const() {
|
||||
return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
|
||||
}
|
||||
tmp := &bpparser.Value{
|
||||
Type: bpparser.String,
|
||||
Variable: name.Value(nil),
|
||||
}
|
||||
|
||||
if val != nil {
|
||||
val, err = addValues(val, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
val = tmp
|
||||
}
|
||||
|
||||
if s != "" {
|
||||
tmp := stringToStringValue(s)
|
||||
val, err = addValues(val, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func stringToListValue(s string) *bpparser.Value {
|
||||
list := strings.Fields(s)
|
||||
valList := make([]bpparser.Value, len(list))
|
||||
for i, l := range list {
|
||||
valList[i] = bpparser.Value{
|
||||
Type: bpparser.String,
|
||||
StringValue: l,
|
||||
}
|
||||
}
|
||||
return &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
ListValue: valList,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func makeToListExpression(ms *mkparser.MakeString) (*bpparser.Value, error) {
|
||||
fields := ms.Split(" \t")
|
||||
|
||||
var listOfListValues []*bpparser.Value
|
||||
|
||||
listValue := &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
}
|
||||
|
||||
for _, f := range fields {
|
||||
if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
|
||||
// Variable by itself, variable is probably a list
|
||||
if !f.Variables[0].Name.Const() {
|
||||
return nil, fmt.Errorf("unsupported non-const variable name")
|
||||
}
|
||||
if len(listValue.ListValue) > 0 {
|
||||
listOfListValues = append(listOfListValues, listValue)
|
||||
}
|
||||
listOfListValues = append(listOfListValues, &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
Variable: f.Variables[0].Name.Value(nil),
|
||||
})
|
||||
listValue = &bpparser.Value{
|
||||
Type: bpparser.List,
|
||||
}
|
||||
} else {
|
||||
s, err := makeToStringExpression(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
listValue.ListValue = append(listValue.ListValue, *s)
|
||||
}
|
||||
}
|
||||
|
||||
if len(listValue.ListValue) > 0 {
|
||||
listOfListValues = append(listOfListValues, listValue)
|
||||
}
|
||||
|
||||
if len(listOfListValues) == 0 {
|
||||
return listValue, nil
|
||||
}
|
||||
|
||||
val := listOfListValues[0]
|
||||
for _, tmp := range listOfListValues[1:] {
|
||||
var err error
|
||||
val, err = addValues(val, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func stringToBoolValue(s string) (*bpparser.Value, error) {
|
||||
var b bool
|
||||
s = strings.TrimSpace(s)
|
||||
switch s {
|
||||
case "true":
|
||||
b = true
|
||||
case "false", "":
|
||||
b = false
|
||||
case "-frtti": // HACK for LOCAL_RTTI_VALUE
|
||||
b = true
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected bool value %s", s)
|
||||
}
|
||||
return &bpparser.Value{
|
||||
Type: bpparser.Bool,
|
||||
BoolValue: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeToBoolExpression(ms *mkparser.MakeString) (*bpparser.Value, error) {
|
||||
if !ms.Const() {
|
||||
if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
|
||||
name := ms.Variables[0].Name
|
||||
if !name.Const() {
|
||||
return nil, fmt.Errorf("unsupported non-const variable name")
|
||||
}
|
||||
return &bpparser.Value{
|
||||
Type: bpparser.Bool,
|
||||
Variable: name.Value(nil),
|
||||
}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("non-const bool expression %s", ms.Dump())
|
||||
}
|
||||
}
|
||||
|
||||
return stringToBoolValue(ms.Value(nil))
|
||||
}
|
Reference in New Issue
Block a user