summaryrefslogtreecommitdiffstats
path: root/vendor/modernc.org/cc/v3/ast2.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/modernc.org/cc/v3/ast2.go')
-rw-r--r--vendor/modernc.org/cc/v3/ast2.go1187
1 files changed, 1187 insertions, 0 deletions
diff --git a/vendor/modernc.org/cc/v3/ast2.go b/vendor/modernc.org/cc/v3/ast2.go
new file mode 100644
index 00000000..13ed6130
--- /dev/null
+++ b/vendor/modernc.org/cc/v3/ast2.go
@@ -0,0 +1,1187 @@
+// Copyright 2019 The CC Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cc // import "modernc.org/cc/v3"
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+// Source is a named part of a translation unit. If Value is empty, Name is
+// interpreted as a path to file containing the source code.
+type Source struct {
+ Name string
+ Value string
+ DoNotCache bool // Disable caching of this source
+}
+
+// Promote returns the type the operands of a binary operation are promoted to
+// or the type and argument passed in a function call is promoted.
+func (n *AssignmentExpression) Promote() Type { return n.promote }
+
+type StructInfo struct {
+ Size uintptr
+
+ Align int
+}
+
+// AST represents a translation unit and its related data.
+type AST struct {
+ Enums map[StringID]Operand // Enumeration constants declared in file scope.
+ Macros map[StringID]*Macro // Macros as defined after parsing.
+ PtrdiffType Type
+ Scope Scope // File scope.
+ SizeType Type
+ StructTypes map[StringID]Type // Tagged struct/union types declared in file scope.
+ // Alignment and size of every struct/union defined in the translation
+ // unit. Valid only after Translate.
+ Structs map[StructInfo]struct{}
+ // TLD contains pruned file scope declarators, ie. either the first one
+ // or the first one that has an initializer.
+ TLD map[*Declarator]struct{}
+ TrailingSeperator StringID // White space and/or comments preceding EOF.
+ TranslationUnit *TranslationUnit
+ WideCharType Type
+ cfg *Config
+ cpp *cpp
+}
+
+// Eval returns the operand that represents the value of m, if it expands to a
+// valid constant expression other than an identifier, or an error, if any.
+func (n *AST) Eval(m *Macro) (o Operand, err error) {
+ defer func() {
+ if e := recover(); e != nil {
+ o = nil
+ err = fmt.Errorf("%v", e)
+ }
+ }()
+
+ if m.IsFnLike() {
+ return nil, fmt.Errorf("cannot evaluate function-like macro")
+ }
+
+ n.cpp.ctx.cfg.ignoreErrors = true
+ n.cpp.ctx.evalIdentError = true
+ v := n.cpp.eval(m.repl)
+ switch x := v.(type) {
+ case int64:
+ return &operand{abi: &n.cfg.ABI, typ: n.cfg.ABI.Type(LongLong), value: Int64Value(x)}, nil
+ case uint64:
+ return &operand{abi: &n.cfg.ABI, typ: n.cfg.ABI.Type(ULongLong), value: Uint64Value(x)}, nil
+ default:
+ return nil, fmt.Errorf("unexpected value: %T", x)
+ }
+}
+
+// Parse preprocesses and parses a translation unit and returns an *AST or
+// error, if any.
+//
+// Search paths listed in includePaths and sysIncludePaths are used to resolve
+// #include "foo.h" and #include <foo.h> preprocessing directives respectively.
+// A special search path "@" is interpreted as 'the same directory as where the
+// file with the #include directive is'.
+//
+// The sources should typically provide, usually in this particular order:
+//
+// - predefined macros, eg.
+//
+// #define __SIZE_TYPE__ long unsigned int
+//
+// - built-in declarations, eg.
+//
+// int __builtin_printf(char *__format, ...);
+//
+// - command-line provided directives, eg.
+//
+// #define FOO
+// #define BAR 42
+// #undef QUX
+//
+// - normal C sources, eg.
+//
+// int main() {}
+//
+// All search and file paths should be absolute paths.
+//
+// If the preprocessed translation unit is empty, the function may return (nil,
+// nil).
+//
+// The parser does only the minimum declarations/identifier resolving necessary
+// for correct parsing. Redeclarations are not checked.
+//
+// Declarators (*Declarator) and StructDeclarators (*StructDeclarator) are
+// inserted in the appropriate scopes.
+//
+// Tagged struct/union specifier definitions (*StructOrUnionSpecifier) are
+// inserted in the appropriate scopes.
+//
+// Tagged enum specifier definitions (*EnumSpecifier) and enumeration constants
+// (*Enumerator) are inserted in the appropriate scopes.
+//
+// Labels (*LabeledStatement) are inserted in the appropriate scopes.
+func Parse(cfg *Config, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) {
+ return parse(newContext(cfg), includePaths, sysIncludePaths, sources)
+}
+
+func parse(ctx *context, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) {
+ if s := ctx.cfg.SharedFunctionDefinitions; s != nil {
+ if s.M == nil {
+ s.M = map[*FunctionDefinition]struct{}{}
+ }
+ if s.m == nil {
+ s.m = map[sharedFunctionDefinitionKey]*FunctionDefinition{}
+ }
+ }
+ if debugWorkingDir || ctx.cfg.DebugWorkingDir {
+ switch wd, err := os.Getwd(); err {
+ case nil:
+ fmt.Fprintf(os.Stderr, "OS working dir: %s\n", wd)
+ default:
+ fmt.Fprintf(os.Stderr, "OS working dir: error %s\n", err)
+ }
+ fmt.Fprintf(os.Stderr, "Config.WorkingDir: %s\n", ctx.cfg.WorkingDir)
+ }
+ if debugIncludePaths || ctx.cfg.DebugIncludePaths {
+ fmt.Fprintf(os.Stderr, "include paths: %v\n", includePaths)
+ fmt.Fprintf(os.Stderr, "system include paths: %v\n", sysIncludePaths)
+ }
+ ctx.includePaths = includePaths
+ ctx.sysIncludePaths = sysIncludePaths
+ var in []source
+ for _, v := range sources {
+ ts, err := cache.get(ctx, v)
+ if err != nil {
+ return nil, err
+ }
+
+ in = append(in, ts)
+ }
+
+ p := newParser(ctx, make(chan *[]Token, 5000)) //DONE benchmark tuned
+ var sep StringID
+ var ssep []byte
+ var seq int32
+ cpp := newCPP(ctx)
+ go func() {
+
+ defer func() {
+ close(p.in)
+ ctx.intMaxWidth = cpp.intMaxWidth()
+ }()
+
+ toks := tokenPool.Get().(*[]Token)
+ *toks = (*toks)[:0]
+ for pline := range cpp.translationPhase4(in) {
+ line := *pline
+ for _, tok := range line {
+ switch tok.char {
+ case ' ', '\n':
+ if ctx.cfg.PreserveOnlyLastNonBlankSeparator {
+ if strings.TrimSpace(tok.value.String()) != "" {
+ sep = tok.value
+ }
+ break
+ }
+
+ switch {
+ case sep != 0:
+ ssep = append(ssep, tok.String()...)
+ default:
+ sep = tok.value
+ ssep = append(ssep[:0], sep.String()...)
+ }
+ default:
+ var t Token
+ t.Rune = tok.char
+ switch {
+ case len(ssep) != 0:
+ t.Sep = dict.id(ssep)
+ default:
+ t.Sep = sep
+ }
+ t.Value = tok.value
+ t.Src = tok.src
+ t.file = tok.file
+ t.macro = tok.macro
+ t.pos = tok.pos
+ seq++
+ t.seq = seq
+ *toks = append(*toks, t)
+ sep = 0
+ ssep = ssep[:0]
+ }
+ }
+ token4Pool.Put(pline)
+ var c rune
+ if n := len(*toks); n != 0 {
+ c = (*toks)[n-1].Rune
+ }
+ switch c {
+ case STRINGLITERAL, LONGSTRINGLITERAL:
+ // nop
+ default:
+ if len(*toks) != 0 {
+ p.in <- translationPhase5(ctx, toks)
+ toks = tokenPool.Get().(*[]Token)
+ *toks = (*toks)[:0]
+ }
+ }
+ }
+ if len(*toks) != 0 {
+ p.in <- translationPhase5(ctx, toks)
+ }
+ }()
+
+ tu := p.translationUnit()
+ if p.errored { // Must drain
+ go func() {
+ for range p.in {
+ }
+ }()
+ }
+
+ if err := ctx.Err(); err != nil {
+ return nil, err
+ }
+
+ if p.errored && !ctx.cfg.ignoreErrors {
+ return nil, fmt.Errorf("%v: syntax error", p.tok.Position())
+ }
+
+ if p.scopes != 0 {
+ panic(internalErrorf("invalid scope nesting but no error reported"))
+ }
+
+ ts := sep
+ if len(ssep) != 0 {
+ ts = dict.id(ssep)
+ }
+ return &AST{
+ Macros: cpp.macros,
+ Scope: p.fileScope,
+ TLD: map[*Declarator]struct{}{},
+ TrailingSeperator: ts,
+ TranslationUnit: tu,
+ cfg: ctx.cfg,
+ cpp: cpp,
+ }, nil
+}
+
+func translationPhase5(ctx *context, toks *[]Token) *[]Token {
+ // [0], 5.1.1.2, 5
+ //
+ // Each source character set member and escape sequence in character
+ // constants and string literals is converted to the corresponding
+ // member of the execution character set; if there is no corresponding
+ // member, it is converted to an implementation- defined member other
+ // than the null (wide) character.
+ for i, tok := range *toks {
+ var cpt cppToken
+ switch tok.Rune {
+ case STRINGLITERAL, LONGSTRINGLITERAL:
+ cpt.char = tok.Rune
+ cpt.value = tok.Value
+ cpt.src = tok.Src
+ cpt.file = tok.file
+ cpt.pos = tok.pos
+ (*toks)[i].Value = dict.sid(stringConst(ctx, cpt))
+ case CHARCONST, LONGCHARCONST:
+ var cpt cppToken
+ cpt.char = tok.Rune
+ cpt.value = tok.Value
+ cpt.src = tok.Src
+ cpt.file = tok.file
+ cpt.pos = tok.pos
+ switch r := charConst(ctx, cpt); {
+ case r <= 255:
+ (*toks)[i].Value = dict.sid(string(r))
+ default:
+ switch cpt.char {
+ case CHARCONST:
+ ctx.err(tok.Position(), "invalid character constant: %s", tok.Value)
+ default:
+ (*toks)[i].Value = dict.sid(string(r))
+ }
+ }
+ }
+ }
+ return toks
+}
+
+// Preprocess preprocesses a translation unit and outputs the result to w.
+//
+// Please see Parse for the documentation of the other parameters.
+func Preprocess(cfg *Config, includePaths, sysIncludePaths []string, sources []Source, w io.Writer) error {
+ ctx := newContext(cfg)
+ if debugWorkingDir || ctx.cfg.DebugWorkingDir {
+ switch wd, err := os.Getwd(); err {
+ case nil:
+ fmt.Fprintf(os.Stderr, "OS working dir: %s\n", wd)
+ default:
+ fmt.Fprintf(os.Stderr, "OS working dir: error %s\n", err)
+ }
+ fmt.Fprintf(os.Stderr, "Config.WorkingDir: %s\n", ctx.cfg.WorkingDir)
+ }
+ if debugIncludePaths || ctx.cfg.DebugIncludePaths {
+ fmt.Fprintf(os.Stderr, "include paths: %v\n", includePaths)
+ fmt.Fprintf(os.Stderr, "system include paths: %v\n", sysIncludePaths)
+ }
+ ctx.includePaths = includePaths
+ ctx.sysIncludePaths = sysIncludePaths
+ var in []source
+ for _, v := range sources {
+ ts, err := cache.get(ctx, v)
+ if err != nil {
+ return err
+ }
+
+ in = append(in, ts)
+ }
+
+ var sep StringID
+ cpp := newCPP(ctx)
+ toks := tokenPool.Get().(*[]Token)
+ *toks = (*toks)[:0]
+ for pline := range cpp.translationPhase4(in) {
+ line := *pline
+ for _, tok := range line {
+ switch tok.char {
+ case ' ', '\n':
+ if ctx.cfg.PreserveOnlyLastNonBlankSeparator {
+ if strings.TrimSpace(tok.value.String()) != "" {
+ sep = tok.value
+ }
+ break
+ }
+
+ switch {
+ case sep != 0:
+ sep = dict.sid(sep.String() + tok.String())
+ default:
+ sep = tok.value
+ }
+ default:
+ var t Token
+ t.Rune = tok.char
+ t.Sep = sep
+ t.Value = tok.value
+ t.Src = tok.src
+ t.file = tok.file
+ t.pos = tok.pos
+ *toks = append(*toks, t)
+ sep = 0
+ }
+ }
+ token4Pool.Put(pline)
+ var c rune
+ if n := len(*toks); n != 0 {
+ c = (*toks)[n-1].Rune
+ }
+ switch c {
+ case STRINGLITERAL, LONGSTRINGLITERAL:
+ // nop
+ default:
+ if len(*toks) != 0 {
+ for _, v := range *translationPhase5(ctx, toks) {
+ if err := wTok(w, v); err != nil {
+ return err
+ }
+ }
+ toks = tokenPool.Get().(*[]Token)
+ *toks = (*toks)[:0]
+ }
+ }
+ }
+ if len(*toks) != 0 {
+ for _, v := range *translationPhase5(ctx, toks) {
+ if err := wTok(w, v); err != nil {
+ return err
+ }
+ }
+ }
+ if _, err := fmt.Fprintln(w); err != nil {
+ return err
+ }
+ return ctx.Err()
+}
+
+func wTok(w io.Writer, tok Token) (err error) {
+ switch tok.Rune {
+ case STRINGLITERAL, LONGSTRINGLITERAL:
+ _, err = fmt.Fprintf(w, `%s"%s"`, tok.Sep, cQuotedString(tok.String(), true))
+ case CHARCONST, LONGCHARCONST:
+ _, err = fmt.Fprintf(w, `%s'%s'`, tok.Sep, cQuotedString(tok.String(), false))
+ default:
+ _, err = fmt.Fprintf(w, "%s%s", tok.Sep, tok)
+ }
+ return err
+}
+
+func cQuotedString(s string, isString bool) []byte {
+ var b []byte
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ switch c {
+ case '\b':
+ b = append(b, '\\', 'b')
+ continue
+ case '\f':
+ b = append(b, '\\', 'f')
+ continue
+ case '\n':
+ b = append(b, '\\', 'n')
+ continue
+ case '\r':
+ b = append(b, '\\', 'r')
+ continue
+ case '\t':
+ b = append(b, '\\', 't')
+ continue
+ case '\\':
+ b = append(b, '\\', '\\')
+ continue
+ case '"':
+ switch {
+ case isString:
+ b = append(b, '\\', '"')
+ default:
+ b = append(b, '"')
+ }
+ continue
+ case '\'':
+ switch {
+ case isString:
+ b = append(b, '\'')
+ default:
+ b = append(b, '\\', '\'')
+ }
+ continue
+ }
+
+ switch {
+ case c < ' ' || c >= 0x7f:
+ b = append(b, '\\', octal(c>>6), octal(c>>3), octal(c))
+ default:
+ b = append(b, c)
+ }
+ }
+ return b
+}
+
+func octal(b byte) byte { return '0' + b&7 }
+
+var trcSource = Source{"<builtin-trc>", `
+extern void *stderr;
+int fflush(void *stream);
+int fprintf(void *stream, const char *format, ...);
+`, false}
+
+// Translate parses and typechecks a translation unit and returns an *AST or
+// error, if any.
+//
+// Please see Parse for the documentation of the parameters.
+func Translate(cfg *Config, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) {
+ if cfg.InjectTracingCode {
+ for i, v := range sources {
+ if filepath.Ext(v.Name) == ".c" {
+ sources = append(append(append([]Source(nil), sources[:i]...), trcSource), sources[i:]...)
+ }
+ }
+ }
+ return translate(newContext(cfg), includePaths, sysIncludePaths, sources)
+}
+
+func translate(ctx *context, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) {
+ ast, err := parse(ctx, includePaths, sysIncludePaths, sources)
+ if err != nil {
+ return nil, err
+ }
+
+ if ctx, err = ast.typecheck(); err != nil {
+ return nil, err
+ }
+
+ ast.PtrdiffType = ptrdiffT(ctx, ast.Scope, Token{})
+ ast.SizeType = sizeT(ctx, ast.Scope, Token{})
+ ast.WideCharType = wcharT(ctx, ast.Scope, Token{})
+ return ast, nil
+}
+
+// Typecheck determines types of objects and expressions and verifies types are
+// valid in the context they are used.
+func (n *AST) Typecheck() error {
+ _, err := n.typecheck()
+ return err
+}
+
+func (n *AST) typecheck() (*context, error) {
+ ctx := newContext(n.cfg)
+ if err := ctx.cfg.ABI.sanityCheck(ctx, int(ctx.intMaxWidth), n.Scope); err != nil {
+ return nil, err
+ }
+
+ ctx.intBits = int(ctx.cfg.ABI.Types[Int].Size) * 8
+ ctx.ast = n
+ n.TranslationUnit.check(ctx)
+ n.Structs = ctx.structs
+ var a []int
+ for k := range n.Scope {
+ a = append(a, int(k))
+ }
+ sort.Ints(a)
+ for _, v := range a {
+ nm := StringID(v)
+ defs := n.Scope[nm]
+ var r, w int
+ for _, v := range defs {
+ switch x := v.(type) {
+ case *Declarator:
+ r += x.Read
+ w += x.Write
+ }
+ }
+ for _, v := range defs {
+ switch x := v.(type) {
+ case *Declarator:
+ x.Read = r
+ x.Write = w
+ }
+ }
+ var pruned *Declarator
+ for _, v := range defs {
+ switch x := v.(type) {
+ case *Declarator:
+ //TODO check compatible types
+ switch {
+ case x.IsExtern() && !x.fnDef:
+ // nop
+ case pruned == nil:
+ pruned = x
+ case pruned.hasInitializer && x.hasInitializer:
+ ctx.errNode(x, "multiple initializers for the same symbol")
+ continue
+ case pruned.fnDef && x.fnDef:
+ ctx.errNode(x, "multiple function definitions")
+ continue
+ case x.hasInitializer || x.fnDef:
+ pruned = x
+ }
+ }
+ }
+ if pruned == nil {
+ continue
+ }
+
+ n.TLD[pruned] = struct{}{}
+ }
+ n.Enums = ctx.enums
+ n.StructTypes = ctx.structTypes
+ return ctx, ctx.Err()
+}
+
+func (n *AlignmentSpecifier) align() int {
+ switch n.Case {
+ case AlignmentSpecifierAlignasType: // "_Alignas" '(' TypeName ')'
+ return n.TypeName.Type().Align()
+ case AlignmentSpecifierAlignasExpr: // "_Alignas" '(' ConstantExpression ')'
+ return n.ConstantExpression.Operand.Type().Align()
+ default:
+ panic(internalError())
+ }
+}
+
+// Closure reports the variables closed over by a nested function (case
+// BlockItemFuncDef).
+func (n *BlockItem) Closure() map[StringID]struct{} { return n.closure }
+
+// FunctionDefinition returns the nested function (case BlockItemFuncDef).
+func (n *BlockItem) FunctionDefinition() *FunctionDefinition { return n.fn }
+
+func (n *Declarator) IsStatic() bool { return n.td != nil && n.td.static() }
+
+// IsImplicit reports whether n was not declared nor defined, only inferred.
+func (n *Declarator) IsImplicit() bool { return n.implicit }
+
+func (n *Declarator) isVisible(at int32) bool { return at == 0 || n.DirectDeclarator.ends() < at }
+
+func (n *Declarator) setLHS(lhs *Declarator) {
+ if n == nil {
+ return
+ }
+
+ if n.lhs == nil {
+ n.lhs = map[*Declarator]struct{}{}
+ }
+ n.lhs[lhs] = struct{}{}
+}
+
+// LHS reports which declarators n is used in assignment RHS or which function
+// declarators n is used in a function argument. To collect this information,
+// TrackAssignments in Config must be set during type checking.
+// The returned map may contain a nil key. That means that n is assigned to a
+// declarator not known at typechecking time.
+func (n *Declarator) LHS() map[*Declarator]struct{} { return n.lhs }
+
+// Called reports whether n is involved in expr in expr(callArgs).
+func (n *Declarator) Called() bool { return n.called }
+
+// FunctionDefinition returns the function definition associated with n, if any.
+func (n *Declarator) FunctionDefinition() *FunctionDefinition {
+ return n.funcDefinition
+}
+
+// NameTok returns n's declaring name token.
+func (n *Declarator) NameTok() (r Token) {
+ if n == nil || n.DirectDeclarator == nil {
+ return r
+ }
+
+ return n.DirectDeclarator.NameTok()
+}
+
+// LexicalScope returns the lexical scope of n.
+func (n *Declarator) LexicalScope() Scope { return n.DirectDeclarator.lexicalScope }
+
+// Name returns n's declared name.
+func (n *Declarator) Name() StringID {
+ if n == nil || n.DirectDeclarator == nil {
+ return 0
+ }
+
+ return n.DirectDeclarator.Name()
+}
+
+// ParamScope returns the scope in which n's function parameters are declared
+// if the underlying type of n is a function or nil otherwise. If n is part of
+// a function definition the scope is the same as the scope of the function
+// body.
+func (n *Declarator) ParamScope() Scope {
+ if n == nil {
+ return nil
+ }
+
+ return n.DirectDeclarator.ParamScope()
+}
+
+// Type returns the type of n.
+func (n *Declarator) Type() Type { return n.typ }
+
+// IsExtern reports whether n was declared with storage class specifier 'extern'.
+func (n *Declarator) IsExtern() bool { return n.td != nil && n.td.extern() }
+
+func (n *DeclarationSpecifiers) auto() bool { return n != nil && n.class&fAuto != 0 }
+func (n *DeclarationSpecifiers) extern() bool { return n != nil && n.class&fExtern != 0 }
+func (n *DeclarationSpecifiers) register() bool { return n != nil && n.class&fRegister != 0 }
+func (n *DeclarationSpecifiers) static() bool { return n != nil && n.class&fStatic != 0 }
+func (n *DeclarationSpecifiers) threadLocal() bool { return n != nil && n.class&fThreadLocal != 0 }
+func (n *DeclarationSpecifiers) typedef() bool { return n != nil && n.class&fTypedef != 0 }
+
+func (n *DirectAbstractDeclarator) TypeQualifier() Type { return n.typeQualifiers }
+
+func (n *DirectDeclarator) ends() int32 {
+ switch n.Case {
+ case DirectDeclaratorIdent: // IDENTIFIER
+ return n.Token.seq
+ case DirectDeclaratorDecl: // '(' Declarator ')'
+ return n.Token2.seq
+ case DirectDeclaratorArr: // DirectDeclarator '[' TypeQualifierList AssignmentExpression ']'
+ return n.Token2.seq
+ case DirectDeclaratorStaticArr: // DirectDeclarator '[' "static" TypeQualifierList AssignmentExpression ']'
+ return n.Token3.seq
+ case DirectDeclaratorArrStatic: // DirectDeclarator '[' TypeQualifierList "static" AssignmentExpression ']'
+ return n.Token3.seq
+ case DirectDeclaratorStar: // DirectDeclarator '[' TypeQualifierList '*' ']'
+ return n.Token3.seq
+ case DirectDeclaratorFuncParam: // DirectDeclarator '(' ParameterTypeList ')'
+ return n.Token2.seq
+ case DirectDeclaratorFuncIdent: // DirectDeclarator '(' IdentifierList ')'
+ return n.Token2.seq
+ default:
+ panic(internalError())
+ }
+}
+
+func (n *DirectDeclarator) TypeQualifier() Type { return n.typeQualifiers }
+
+// NameTok returns n's declarin name token.
+func (n *DirectDeclarator) NameTok() (r Token) {
+ for {
+ if n == nil {
+ return r
+ }
+
+ switch n.Case {
+ case DirectDeclaratorIdent: // IDENTIFIER
+ return n.Token
+ case DirectDeclaratorDecl: // '(' Declarator ')'
+ return n.Declarator.NameTok()
+ default:
+ n = n.DirectDeclarator
+ }
+ }
+}
+
+// Name returns n's declared name.
+func (n *DirectDeclarator) Name() StringID {
+ for {
+ if n == nil {
+ return 0
+ }
+
+ switch n.Case {
+ case DirectDeclaratorIdent: // IDENTIFIER
+ return n.Token.Value
+ case DirectDeclaratorDecl: // '(' Declarator ')'
+ return n.Declarator.Name()
+ default:
+ n = n.DirectDeclarator
+ }
+ }
+}
+
+// ParamScope returns the innermost scope in which function parameters are
+// declared for Case DirectDeclaratorFuncParam or DirectDeclaratorFuncIdent or
+// nil otherwise.
+func (n *DirectDeclarator) ParamScope() Scope {
+ if n == nil {
+ return nil
+ }
+
+ switch n.Case {
+ case DirectDeclaratorIdent: // IDENTIFIER
+ return nil
+ case DirectDeclaratorDecl: // '(' Declarator ')'
+ return n.Declarator.ParamScope()
+ case DirectDeclaratorArr: // DirectDeclarator '[' TypeQualifierList AssignmentExpression ']'
+ return n.DirectDeclarator.ParamScope()
+ case DirectDeclaratorStaticArr: // DirectDeclarator '[' "static" TypeQualifierList AssignmentExpression ']'
+ return n.DirectDeclarator.ParamScope()
+ case DirectDeclaratorArrStatic: // DirectDeclarator '[' TypeQualifierList "static" AssignmentExpression ']'
+ return n.DirectDeclarator.ParamScope()
+ case DirectDeclaratorStar: // DirectDeclarator '[' TypeQualifierList '*' ']'
+ return n.DirectDeclarator.ParamScope()
+ case DirectDeclaratorFuncParam: // DirectDeclarator '(' ParameterTypeList ')'
+ if s := n.DirectDeclarator.ParamScope(); s != nil {
+ return s
+ }
+
+ return n.paramScope
+ case DirectDeclaratorFuncIdent: // DirectDeclarator '(' IdentifierList ')'
+ if s := n.DirectDeclarator.ParamScope(); s != nil {
+ return s
+ }
+
+ return n.paramScope
+ default:
+ panic(internalError())
+ }
+}
+
+func (n *Enumerator) isVisible(at int32) bool { return n.Token.seq < at }
+
+func (n *EnumSpecifier) Type() Type { return n.typ }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *EqualityExpression) Promote() Type { return n.promote }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *AdditiveExpression) Promote() Type { return n.promote }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *MultiplicativeExpression) Promote() Type { return n.promote }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *InclusiveOrExpression) Promote() Type { return n.promote }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *ExclusiveOrExpression) Promote() Type { return n.promote }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *AndExpression) Promote() Type { return n.promote }
+
+func (n *InitDeclarator) Value() *InitializerValue { return n.initializer }
+
+// FirstDesignatorField returns the first field a designator of an union type
+// denotes, if any.
+func (n *Initializer) FirstDesignatorField() Field { return n.field0 }
+
+// TrailingComma returns the comma token following n, if any.
+func (n *Initializer) TrailingComma() *Token { return n.trailingComma }
+
+// IsConst reports whether n is constant.
+func (n *Initializer) IsConst() bool { return n == nil || n.isConst }
+
+// IsZero reports whether n is a zero value.
+func (n *Initializer) IsZero() bool { return n == nil || n.isZero }
+
+// List returns n as a flattened list of all items that are case
+// InitializerExpr.
+func (n *Initializer) List() []*Initializer { return n.list }
+
+// Parent returns the parent of n, if any.
+func (n *Initializer) Parent() *Initializer { return n.parent }
+
+// Type returns the type this initializer initializes.
+func (n *Initializer) Type() Type { return n.typ }
+
+// IsConst reports whether n is constant.
+func (n *InitializerList) IsConst() bool { return n == nil || n.isConst }
+
+// IsZero reports whether n is a zero value.
+func (n *InitializerList) IsZero() bool { return n == nil || n.isZero }
+
+// List returns n as a flattened list of all items that are case
+// InitializerExpr.
+func (n *InitializerList) List() []*Initializer {
+ if n == nil {
+ return nil
+ }
+
+ return n.list
+}
+
+// IsEmpty reprts whether n is an empty list.
+func (n *InitializerList) IsEmpty() bool { return len(n.list) == 0 }
+
+// LexicalScope returns the lexical scope of n.
+func (n *JumpStatement) LexicalScope() Scope { return n.lexicalScope }
+
+// LexicalScope returns the lexical scope of n.
+func (n *LabeledStatement) LexicalScope() Scope { return n.lexicalScope }
+
+func (n *ParameterDeclaration) Type() Type { return n.typ }
+
+func (n *Pointer) TypeQualifier() Type { return n.typeQualifiers }
+
+// ResolvedIn reports which scope the identifier of cases
+// PrimaryExpressionIdent, PrimaryExpressionEnum were resolved in, if any.
+func (n *PrimaryExpression) ResolvedIn() Scope { return n.resolvedIn }
+
+// ResolvedTo reports which Node the identifier of cases
+// PrimaryExpressionIdent, PrimaryExpressionEnum resolved to, if any.
+func (n *PrimaryExpression) ResolvedTo() Node { return n.resolvedTo }
+
+// Promote returns the type the operands of the binary operation are promoted to.
+func (n *RelationalExpression) Promote() Type { return n.promote }
+
+// Cases returns the cases a switch statement consist of, in source order.
+func (n *SelectionStatement) Cases() []*LabeledStatement { return n.cases }
+
+// Promote returns the type the shift count operand is promoted to.
+func (n *ShiftExpression) Promote() Type { return n.promote }
+
+func (n *StructOrUnionSpecifier) Type() Type { return n.typ }
+
+// Promote returns the type the type the switch expression is promoted to.
+func (n *SelectionStatement) Promote() Type { return n.promote }
+
+// Type returns the type of n.
+func (n *TypeName) Type() Type { return n.typ }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *AttributeValue) LexicalScope() Scope { return n.lexicalScope }
+
+// // Scope returns n's scope.
+// func (n *CompoundStatement) Scope() Scope { return n.scope }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *Designator) LexicalScope() Scope { return n.lexicalScope }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *DirectDeclarator) LexicalScope() Scope { return n.lexicalScope }
+
+// LexicalScope returns the lexical scope of n.
+func (n *EnumSpecifier) LexicalScope() Scope { return n.lexicalScope }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *IdentifierList) LexicalScope() Scope { return n.lexicalScope }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *PrimaryExpression) LexicalScope() Scope { return n.lexicalScope }
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *StructOrUnionSpecifier) LexicalScope() Scope { return n.lexicalScope }
+
+// // ResolvedIn reports which scope the identifier of case
+// // TypeSpecifierTypedefName was resolved in, if any.
+// func (n *TypeSpecifier) ResolvedIn() Scope { return n.resolvedIn }
+
+func (n *TypeSpecifier) list() (r []*TypeSpecifier) {
+ switch n.Case {
+ case TypeSpecifierAtomic:
+ return n.AtomicTypeSpecifier.list
+ default:
+ return []*TypeSpecifier{n}
+ }
+}
+
+// // LexicalScope returns the lexical scope of n.
+// func (n *UnaryExpression) LexicalScope() Scope { return n.lexicalScope }
+
+func (n *UnaryExpression) Declarator() *Declarator {
+ switch n.Case {
+ case UnaryExpressionPostfix: // PostfixExpression
+ return n.PostfixExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *PostfixExpression) Declarator() *Declarator {
+ switch n.Case {
+ case PostfixExpressionPrimary: // PrimaryExpression
+ return n.PrimaryExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *PrimaryExpression) Declarator() *Declarator {
+ switch n.Case {
+ case PrimaryExpressionIdent: // IDENTIFIER
+ if n.Operand != nil {
+ return n.Operand.Declarator()
+ }
+
+ return nil
+ case PrimaryExpressionExpr: // '(' Expression ')'
+ return n.Expression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *Expression) Declarator() *Declarator {
+ switch n.Case {
+ case ExpressionAssign: // AssignmentExpression
+ return n.AssignmentExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *AssignmentExpression) Declarator() *Declarator {
+ switch n.Case {
+ case AssignmentExpressionCond: // ConditionalExpression
+ return n.ConditionalExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *ConditionalExpression) Declarator() *Declarator {
+ switch n.Case {
+ case ConditionalExpressionLOr: // LogicalOrExpression
+ return n.LogicalOrExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *LogicalOrExpression) Declarator() *Declarator {
+ switch n.Case {
+ case LogicalOrExpressionLAnd: // LogicalAndExpression
+ return n.LogicalAndExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *LogicalAndExpression) Declarator() *Declarator {
+ switch n.Case {
+ case LogicalAndExpressionOr: // InclusiveOrExpression
+ return n.InclusiveOrExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *InclusiveOrExpression) Declarator() *Declarator {
+ switch n.Case {
+ case InclusiveOrExpressionXor: // ExclusiveOrExpression
+ return n.ExclusiveOrExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *ExclusiveOrExpression) Declarator() *Declarator {
+ switch n.Case {
+ case ExclusiveOrExpressionAnd: // AndExpression
+ return n.AndExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *AndExpression) Declarator() *Declarator {
+ switch n.Case {
+ case AndExpressionEq: // EqualityExpression
+ return n.EqualityExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *EqualityExpression) Declarator() *Declarator {
+ switch n.Case {
+ case EqualityExpressionRel: // RelationalExpression
+ return n.RelationalExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *RelationalExpression) Declarator() *Declarator {
+ switch n.Case {
+ case RelationalExpressionShift: // ShiftExpression
+ return n.ShiftExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *ShiftExpression) Declarator() *Declarator {
+ switch n.Case {
+ case ShiftExpressionAdd: // AdditiveExpression
+ return n.AdditiveExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *AdditiveExpression) Declarator() *Declarator {
+ switch n.Case {
+ case AdditiveExpressionMul: // MultiplicativeExpression
+ return n.MultiplicativeExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *MultiplicativeExpression) Declarator() *Declarator {
+ switch n.Case {
+ case MultiplicativeExpressionCast: // CastExpression
+ return n.CastExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+func (n *CastExpression) Declarator() *Declarator {
+ switch n.Case {
+ case CastExpressionUnary: // UnaryExpression
+ return n.UnaryExpression.Declarator()
+ default:
+ return nil
+ }
+}
+
+// Has reports whether n has any of attributes in key.
+func (n *AttributeSpecifier) Has(key ...StringID) (*ExpressionList, bool) {
+ if n == nil {
+ return nil, false
+ }
+
+ for list := n.AttributeValueList; list != nil; list = list.AttributeValueList {
+ av := list.AttributeValue
+ for _, k := range key {
+ if av.Token.Value == k {
+ switch av.Case {
+ case AttributeValueIdent: // IDENTIFIER
+ return nil, true
+ case AttributeValueExpr: // IDENTIFIER '(' ExpressionList ')'
+ return av.ExpressionList, true
+ }
+ }
+ }
+ }
+ return nil, false
+}
+
+// Has reports whether n has any of attributes in key.
+func (n *AttributeSpecifierList) Has(key ...StringID) (*ExpressionList, bool) {
+ for ; n != nil; n = n.AttributeSpecifierList {
+ if exprList, ok := n.AttributeSpecifier.Has(key...); ok {
+ return exprList, ok
+ }
+ }
+ return nil, false
+}
+
+// Parent returns the CompoundStatement that contains n, if any.
+func (n *CompoundStatement) Parent() *CompoundStatement { return n.parent }
+
+// IsJumpTarget returns whether n or any of its children contain a named
+// labeled statement.
+func (n *CompoundStatement) IsJumpTarget() bool { return n.isJumpTarget }
+
+func (n *CompoundStatement) hasLabel() {
+ for ; n != nil; n = n.parent {
+ n.isJumpTarget = true
+ }
+}
+
+// Declarations returns the list of declarations in n.
+func (n *CompoundStatement) Declarations() []*Declaration { return n.declarations }
+
+// Children returns the list of n's children.
+func (n *CompoundStatement) Children() []*CompoundStatement { return n.children }
+
+// CompoundStatements returns the list of compound statements in n.
+func (n *FunctionDefinition) CompoundStatements() []*CompoundStatement { return n.compoundStatements }
+
+// CompoundStatement returns the block containing n.
+func (n *LabeledStatement) CompoundStatement() *CompoundStatement { return n.block }
+
+// LabeledStatements returns labeled statements of n.
+func (n *CompoundStatement) LabeledStatements() []*LabeledStatement { return n.labeledStmts }
+
+// HasInitializer reports whether d has an initializator.
+func (n *Declarator) HasInitializer() bool { return n.hasInitializer }
+
+// Context reports the statement, if any, a break or continue belongs to. Valid
+// only after typecheck and for n.Case == JumpStatementBreak or
+// JumpStatementContinue.
+func (n *JumpStatement) Context() Node { return n.context }
+
+// IsFunctionPrototype reports whether n is a function prototype.
+func (n *Declarator) IsFunctionPrototype() bool {
+ return n != nil && n.Type() != nil && n.Type().Kind() == Function && !n.fnDef && !n.IsParameter
+}
+
+// DeclarationSpecifiers returns the declaration specifiers associated with n or nil.
+func (n *Declarator) DeclarationSpecifiers() *DeclarationSpecifiers {
+ if x, ok := n.td.(*DeclarationSpecifiers); ok {
+ return x
+ }
+
+ return nil
+}
+
+// SpecifierQualifierList returns the specifier qualifer list associated with n or nil.
+func (n *Declarator) SpecifierQualifierList() *SpecifierQualifierList {
+ if x, ok := n.td.(*SpecifierQualifierList); ok {
+ return x
+ }
+
+ return nil
+}
+
+// TypeQualifier returns the type qualifiers associated with n or nil.
+func (n *Declarator) TypeQualifiers() *TypeQualifiers {
+ if x, ok := n.td.(*TypeQualifiers); ok {
+ return x
+ }
+
+ return nil
+}
+
+// StructDeclaration returns the struct declaration associated with n.
+func (n *StructDeclarator) StructDeclaration() *StructDeclaration { return n.decl }