2022-01-30 23:27:37 +00:00
// 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"
"go/token"
"math"
"math/big"
"math/bits"
"path/filepath"
"strconv"
"strings"
"modernc.org/mathutil"
"modernc.org/strutil"
)
const longDoublePrec = 256
type mode = int
var (
idBuiltinConstantPImpl = dict . sid ( "__builtin_constant_p_impl" )
idClosure = dict . sid ( "0closure" ) // Must be invalid indentifier.
idWcharT = dict . sid ( "wchar_t" )
idWinWchar = dict . sid ( "WCHAR" )
_ fmt . State
)
const (
// [2], 6.6 Constant expressions, 6
//
// An integer constant expression shall have integer type and shall
// only have operands that are integer constants, enumeration
// constants, character constants, sizeof expressions whose results are
// integer constants, _Alignof expressions, and floating constants that
// are the immediate operands of casts. Cast operators in an integer
// constant expression shall only convert arithmetic types to integer
// types, except as part of an operand to the sizeof or _Alignof
// operator.
mIntConstExpr = 1 << iota
mIntConstExprFloat // As mIntConstExpr plus accept floating point constants.
mIntConstExprAnyCast // As mIntConstExpr plus accept any cast.
)
// Parameter represents a function parameter.
type Parameter struct {
d * Declarator
typ Type
}
// NewParameter returns a newly created parameter
func NewParameter ( d * Declarator , t Type ) * Parameter {
return & Parameter { d , t }
}
func ( p * Parameter ) Declarator ( ) * Declarator { return p . d }
func ( p * Parameter ) Name ( ) StringID { return p . d . Name ( ) }
func ( p * Parameter ) Type ( ) Type { return p . typ }
func ( n * TranslationUnit ) check ( ctx * context ) {
for n := n ; n != nil ; n = n . TranslationUnit {
n . ExternalDeclaration . check ( ctx )
}
for ; n != nil ; n = n . TranslationUnit {
n . ExternalDeclaration . checkFnBodies ( ctx )
}
}
func ( n * ExternalDeclaration ) checkFnBodies ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case ExternalDeclarationFuncDef : // FunctionDefinition
n . FunctionDefinition . checkBody ( ctx )
}
}
// https://gcc.gnu.org/onlinedocs/gcc/Inline.html
//
// If you specify both inline and extern in the function definition, then the
// definition is used only for inlining. In no case is the function compiled on
// its own, not even if you refer to its address explicitly. Such an address
// becomes an external reference, as if you had only declared the function, and
// had not defined it.
//
// This combination of inline and extern has almost the effect of a macro. The
// way to use it is to put a function definition in a header file with these
// keywords, and put another copy of the definition (lacking inline and extern)
// in a library file. The definition in the header file causes most calls to
// the function to be inlined. If any uses of the function remain, they refer
// to the single copy in the library.
func ( n * Declarator ) isExternInline ( ) bool {
return n . IsExtern ( ) && n . Type ( ) != nil && n . Type ( ) . Inline ( )
}
// DeclarationSpecifiers Declarator DeclarationList CompoundStatement
func ( n * FunctionDefinition ) checkBody ( ctx * context ) {
if n == nil {
return
}
if n . checked {
return
}
n . checked = true
if n . Declarator . isExternInline ( ) && ! ctx . cfg . CheckExternInlineFnBodies {
return
}
ctx . checkFn = n
rd := ctx . readDelta
ctx . readDelta = 1
n . CompoundStatement . check ( ctx )
ctx . checkFn = nil
for k , v := range n . ComputedGotos {
if _ , ok := n . Labels [ k ] ; ! ok {
ctx . errNode ( v , "label %s undefined" , k )
}
}
for k , v := range n . Gotos {
if _ , ok := n . Labels [ k ] ; ! ok {
ctx . errNode ( v , "label %s undefined" , k )
}
}
for _ , n := range n . InitDeclarators {
d := n . Declarator
if d . Type ( ) . IsIncomplete ( ) && d . Linkage != External {
ctx . errNode ( d , "declarator has incomplete type" )
}
if ctx . cfg . RejectUninitializedDeclarators && d . Linkage == None && d . Write == 0 && ! d . AddressTaken && d . Read != 0 {
switch d . Type ( ) . Kind ( ) {
case Array , Struct , Union , Invalid :
// nop
default :
ctx . errNode ( d , "%s may be used uninitialized in this function" , d . Name ( ) )
}
}
}
for _ , n := range n . CompositeLiterals {
switch t := n . Operand . Type ( ) ; t . Kind ( ) {
case Invalid :
ctx . errNode ( n , "composite literal has invalid type" )
default :
if t . IsIncomplete ( ) {
ctx . errNode ( n , "composite literal has incomplete type" )
}
}
}
ctx . readDelta = rd
}
func ( n * ExternalDeclaration ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case ExternalDeclarationFuncDef : // FunctionDefinition
n . FunctionDefinition . checkDeclarator ( ctx )
case ExternalDeclarationDecl : // Declaration
n . Declaration . check ( ctx , true )
case ExternalDeclarationAsm : // AsmFunctionDefinition
n . AsmFunctionDefinition . check ( ctx )
case ExternalDeclarationAsmStmt : // AsmStatement
n . AsmStatement . check ( ctx )
case ExternalDeclarationEmpty : // ';'
// nop
case ExternalDeclarationPragma : // PragmaSTDC
n . PragmaSTDC . check ( ctx )
default :
panic ( todo ( "" ) )
}
}
func ( n * PragmaSTDC ) check ( ctx * context ) {
// nop
}
func ( n * AsmFunctionDefinition ) check ( ctx * context ) {
if n == nil {
return
}
typ , inline , noret := n . DeclarationSpecifiers . check ( ctx , false )
typ . setFnSpecs ( inline , noret )
n . Declarator . check ( ctx , n . DeclarationSpecifiers , typ , true )
n . AsmStatement . check ( ctx )
}
func ( n * AsmStatement ) check ( ctx * context ) {
if n == nil {
return
}
n . Asm . check ( ctx )
n . AttributeSpecifierList . check ( ctx , nil )
}
func ( n * Declaration ) check ( ctx * context , tld bool ) {
if n == nil {
return
}
typ , _ , _ := n . DeclarationSpecifiers . check ( ctx , false )
n . InitDeclaratorList . check ( ctx , n . DeclarationSpecifiers , typ , tld )
}
func ( n * InitDeclaratorList ) check ( ctx * context , td typeDescriptor , typ Type , tld bool ) {
for ; n != nil ; n = n . InitDeclaratorList {
n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) )
n . InitDeclarator . check ( ctx , td , typ , tld )
}
}
func ( n * InitDeclarator ) check ( ctx * context , td typeDescriptor , typ Type , tld bool ) {
if n == nil {
return
}
if f := ctx . checkFn ; f != nil {
f . InitDeclarators = append ( f . InitDeclarators , n )
}
if attr := n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) ) ; len ( attr ) != 0 {
typ = & attributedType { typ , attr }
}
switch n . Case {
case InitDeclaratorDecl : // Declarator AttributeSpecifierList
n . Declarator . check ( ctx , td , typ , tld )
case InitDeclaratorInit : // Declarator AttributeSpecifierList '=' Initializer
typ := n . Declarator . check ( ctx , td , typ , tld )
n . Declarator . hasInitializer = true
n . Declarator . Write ++
n . Initializer . check ( ctx , & n . Initializer . list , typ , n . Declarator . StorageClass , nil , 0 , nil , nil , false )
n . Initializer . setConstZero ( )
n . initializer = & InitializerValue { typ : typ , initializer : n . Initializer }
if ctx . cfg . TrackAssignments {
setLHS ( map [ * Declarator ] struct { } { n . Declarator : { } } , n . Initializer )
}
default :
panic ( todo ( "" ) )
}
}
func ( n * Initializer ) setConstZero ( ) {
switch n . Case {
case InitializerExpr : // AssignmentExpression
if op := n . AssignmentExpression . Operand ; op != nil {
n . isConst = op . IsConst ( )
n . isZero = op . IsZero ( )
}
case InitializerInitList : // '{' InitializerList ',' '}'
li := n . InitializerList
li . setConstZero ( )
n . isConst = li . IsConst ( )
n . isZero = li . IsZero ( )
default :
panic ( todo ( "%v:" , n . Position ( ) ) )
}
}
func ( n * InitializerList ) setConstZero ( ) {
if n == nil {
return
}
n0 := n
n0 . isConst = true
n0 . isZero = true
for ; n != nil ; n = n . InitializerList {
in := n . Initializer
in . setConstZero ( )
n0 . isConst = n0 . isConst && in . isConst
n0 . isZero = n0 . isZero && in . isZero
}
}
// [0], 6.7.8 Initialization
func ( n * Initializer ) check ( ctx * context , list * [ ] * Initializer , t Type , sc StorageClass , fld Field , off uintptr , il * InitializerList , designatorList * DesignatorList , inList bool ) * InitializerList {
// trc("==== %v: case %v, t %v, off %v, designatorList != nil %v, inList %v", n.Position(), n.Case, t.Alias(), off, designatorList != nil, inList)
// if fld != nil {
// trc("\tfld %q", fld.Name())
// }
// 3 - The type of the entity to be initialized shall be an array of
// unknown size or an object type that is not a variable length array
// type.
if t . Kind ( ) == Array && t . IsVLA ( ) {
ctx . errNode ( n , "cannot initialize a variable length array: %v" , t )
if il != nil {
return il . InitializerList
}
return nil
}
defer func ( d int ) { ctx . readDelta = d } ( ctx . readDelta )
ctx . readDelta = 1
n . typ = t
single := n . single ( )
var op Operand
if single != nil {
op = single . AssignmentExpression . check ( ctx , false )
single . typ = t
single . Field = fld
single . Offset = off
}
// 11: The initializer for a scalar shall be a single expression, optionally
// enclosed in braces. The initial value of the object is that of the
// expression (after conversion); the same type constraints and conversions as
// for simple assignment apply, taking the type of the scalar to be the
// unqualified version of its declared type.
if t . IsScalarType ( ) && single != nil {
if designatorList != nil {
panic ( todo ( "" , n . Position ( ) ) )
}
//TODO check compatible
* list = append ( * list , single )
switch {
case t . Kind ( ) == op . Type ( ) . Kind ( ) :
single . AssignmentExpression . InitializerOperand = op
default :
single . AssignmentExpression . InitializerOperand = op . convertTo ( ctx , n , t )
}
if il != nil {
return il . InitializerList
}
return nil
}
// 12: The rest of this subclause deals with initializers for objects that have
// aggregate or union type.
k := t . Kind ( )
// 13: The initializer for a structure or union object that has automatic
// storage duration shall be either an initializer list as described below, or
// a single expression that has compatible structure or union type. In the
// latter case, the initial value of the object, including unnamed members, is
// that of the expression.
if n . Case == InitializerExpr && sc == Automatic && ( k == Struct || k == Union || k == Vector ) && t . IsCompatible ( op . Type ( ) ) {
if designatorList != nil {
panic ( todo ( "" , n . Position ( ) ) )
}
* list = append ( * list , single )
if il != nil {
return il . InitializerList
}
return nil
}
if k == Array && single != nil {
et := t . Elem ( )
switch {
case isCharType ( et ) :
// 14: An array of character type may be initialized by a character string
// literal, optionally enclosed in braces. Successive characters of the
// character string literal (including the terminating null character if there
// is room or if the array is of unknown size) initialize the elements of the
// array.
if x , ok := op . Value ( ) . ( StringValue ) ; ok {
if designatorList != nil {
panic ( todo ( "" , n . Position ( ) ) )
}
* list = append ( * list , single )
str := StringID ( x ) . String ( )
if t . IsIncomplete ( ) {
t . setLen ( uintptr ( len ( str ) ) + 1 )
}
if il != nil {
return il . InitializerList
}
return nil
}
case isWCharType ( et ) :
// 15: An array with element type compatible with wchar_t may be initialized by
// a wide string literal, optionally enclosed in braces. Successive wide
// characters of the wide string literal (including the terminating null wide
// character if there is room or if the array is of unknown size) initialize
// the elements of the array.
if x , ok := op . Value ( ) . ( WideStringValue ) ; ok {
if designatorList != nil {
panic ( todo ( "" , n . Position ( ) ) )
}
* list = append ( * list , single )
str := [ ] rune ( StringID ( x ) . String ( ) )
if t . IsIncomplete ( ) {
t . setLen ( uintptr ( len ( str ) ) + 1 )
}
if il != nil {
panic ( todo ( "" ) )
}
return nil
}
}
}
// 16: Otherwise, the initializer for an object that has aggregate or union
// type shall be a brace-enclosed list of initializers for the elements or
// named members.
if n . Case == InitializerExpr {
if il != nil {
switch t . Kind ( ) {
case Array :
return il . checkArray ( ctx , list , t , sc , off , designatorList , inList )
case Struct :
return il . checkStruct ( ctx , list , t , sc , off , designatorList , inList )
case Union :
return il . checkUnion ( ctx , list , t , sc , off , designatorList , inList )
case Vector :
return il . InitializerList //TODO
default :
panic ( todo ( "" , n . Position ( ) , t , t . Kind ( ) ) )
}
}
var l * InitializerList
Inspect ( n . AssignmentExpression , func ( m Node , b bool ) bool {
if x , ok := m . ( * PostfixExpression ) ; ok && x . Case == PostfixExpressionComplit {
if ! b {
return true
}
if l == nil {
l = x . InitializerList
return true
}
l = nil
return false
}
return true
} )
if l != nil {
l . check ( ctx , list , t , sc , off , designatorList , inList )
return nil
}
ctx . errNode ( n , "initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members: %v" , t )
return nil
}
n . InitializerList . check ( ctx , list , t , sc , off , designatorList , inList )
if il != nil {
return il . InitializerList
}
return nil
}
func ( n * InitializerList ) checkArray ( ctx * context , list * [ ] * Initializer , t Type , sc StorageClass , off uintptr , designatorList * DesignatorList , inList bool ) * InitializerList {
elem := t . Elem ( )
esz := elem . Size ( )
length := t . Len ( )
var i , maxI uintptr
nestedDesignator := designatorList != nil
retOnDesignator := false
loop :
for n != nil {
switch {
case retOnDesignator && n . Designation != nil :
return n
case designatorList == nil && ! inList && n . Designation != nil :
designatorList = n . Designation . DesignatorList
fallthrough
case designatorList != nil :
d := designatorList . Designator
designatorList = designatorList . DesignatorList
switch d . Case {
case DesignatorIndex : // '[' ConstantExpression ']'
switch x := d . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false ) . Value ( ) . ( type ) {
case Int64Value :
i = uintptr ( x )
case Uint64Value :
i = uintptr ( x )
default :
panic ( todo ( "%v: %T" , n . Position ( ) , x ) )
}
if ! inList && i > maxI {
maxI = i
}
case DesignatorField : // '.' IDENTIFIER
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
case DesignatorField2 : // IDENTIFIER ':'
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
default :
panic ( todo ( "" ) )
}
n = n . Initializer . check ( ctx , list , elem , sc , nil , off + i * esz , n , designatorList , designatorList != nil )
designatorList = nil
if nestedDesignator {
retOnDesignator = true
}
i ++
default :
if ! t . IsIncomplete ( ) && i >= length {
break loop
}
if i > maxI {
maxI = i
}
n = n . Initializer . check ( ctx , list , elem , sc , nil , off + i * esz , n , nil , inList )
i ++
}
}
if t . IsIncomplete ( ) {
t . setLen ( maxI + 1 )
}
return n
}
func ( n * InitializerList ) checkStruct ( ctx * context , list * [ ] * Initializer , t Type , sc StorageClass , off uintptr , designatorList * DesignatorList , inList bool ) * InitializerList {
// trc("==== (A) %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList)
// defer trc("==== (Z) %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList)
t = t . underlyingType ( )
// trc("%v: %v, off %v", n.Position(), t, off) //TODO-
nf := t . NumField ( )
i := [ ] int { 0 }
var f Field
nestedDesignator := designatorList != nil
retOnDesignator := false
for n != nil {
switch {
case retOnDesignator && n . Designation != nil :
return n
case designatorList == nil && ! inList && n . Designation != nil :
designatorList = n . Designation . DesignatorList
fallthrough
case designatorList != nil :
d := designatorList . Designator
designatorList = designatorList . DesignatorList
var nm StringID
switch d . Case {
case DesignatorIndex : // '[' ConstantExpression ']'
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
case DesignatorField : // '.' IDENTIFIER
nm = d . Token2 . Value
case DesignatorField2 : // IDENTIFIER ':'
nm = d . Token . Value
default :
panic ( todo ( "" ) )
}
f , xa , ok := t . FieldByName2 ( nm )
if ! ok {
panic ( todo ( "%v: t %v %q" , d . Position ( ) , t , nm ) )
}
t0 := t
switch {
case len ( xa ) != 1 :
var f2 Field
var off2 uintptr
for len ( xa ) != 1 {
f2 = t . FieldByIndex ( xa [ : 1 ] )
off2 += f2 . Offset ( )
t = f2 . Type ( )
xa = xa [ 1 : ]
}
n = n . Initializer . check ( ctx , list , t , sc , f , off + off2 , n , designatorList , designatorList != nil )
if t . Kind ( ) == Union {
t = t0
}
default :
n = n . Initializer . check ( ctx , list , f . Type ( ) , sc , f , off + f . Offset ( ) , n , designatorList , designatorList != nil )
}
designatorList = nil
if nestedDesignator {
retOnDesignator = true
}
i [ 0 ] = xa [ 0 ] + 1
default :
// [0], 6.7.8 Initialization
//
// 9 - Except where explicitly stated otherwise, for the
// purposes of this subclause unnamed members of objects of
// structure and union type do not participate in
// initialization. Unnamed members of structure objects have
// indeterminate value even after initialization.
for ; ; i [ 0 ] ++ {
if i [ 0 ] >= nf {
return n
}
f = t . FieldByIndex ( i )
if f . Name ( ) != 0 || ! f . Type ( ) . IsBitFieldType ( ) {
n = n . Initializer . check ( ctx , list , f . Type ( ) , sc , f , off + f . Offset ( ) , n , nil , inList )
i [ 0 ] ++
break
}
}
}
}
return n
}
func spos ( n Node ) string {
p := n . Position ( )
p . Filename = filepath . Base ( p . Filename )
return p . String ( )
}
func ( n * InitializerList ) checkUnion ( ctx * context , list * [ ] * Initializer , t Type , sc StorageClass , off uintptr , designatorList * DesignatorList , inList bool ) * InitializerList {
// trc("==== %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList)
t = t . underlyingType ( )
// trc("%v: %v, off %v", n.Position(), t, off) //TODO-
nf := t . NumField ( )
i := [ ] int { 0 }
for pass := 0 ; n != nil ; pass ++ {
switch {
case designatorList == nil && ! inList && n . Designation != nil :
designatorList = n . Designation . DesignatorList
fallthrough
case designatorList != nil :
d := designatorList . Designator
designatorList = designatorList . DesignatorList
var nm StringID
switch d . Case {
case DesignatorIndex : // '[' ConstantExpression ']'
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
case DesignatorField : // '.' IDENTIFIER
nm = d . Token2 . Value
case DesignatorField2 : // IDENTIFIER ':'
nm = d . Token . Value
default :
panic ( todo ( "" ) )
}
f , xa , ok := t . FieldByName2 ( nm )
if ! ok {
panic ( todo ( "" , d . Position ( ) ) )
}
if ! inList && pass == 0 {
n . Initializer . field0 = f
}
switch {
case len ( xa ) != 1 :
var f2 Field
var off2 uintptr
for len ( xa ) != 1 {
f2 = t . FieldByIndex ( xa [ : 1 ] )
off2 += f2 . Offset ( )
t = f2 . Type ( )
xa = xa [ 1 : ]
}
next := n . Initializer . check ( ctx , list , t , sc , f , off + off2 + f . Offset ( ) , n , designatorList , designatorList != nil )
if designatorList != nil && designatorList . DesignatorList != nil {
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
}
return next
default :
next := n . Initializer . check ( ctx , list , f . Type ( ) , sc , f , off + f . Offset ( ) , n , designatorList , designatorList != nil )
if designatorList != nil && designatorList . DesignatorList != nil {
panic ( todo ( "" , n . Position ( ) , d . Position ( ) ) )
}
return next
}
default :
// [0], 6.7.8 Initialization
//
// 9 - Except where explicitly stated otherwise, for the
// purposes of this subclause unnamed members of objects of
// structure and union type do not participate in
// initialization. Unnamed members of structure objects have
// indeterminate value even after initialization.
for ; ; i [ 0 ] ++ {
if i [ 0 ] >= nf {
panic ( todo ( "" ) )
}
f := t . FieldByIndex ( i )
if f . Name ( ) != 0 || ! f . Type ( ) . IsBitFieldType ( ) {
next := n . Initializer . check ( ctx , list , f . Type ( ) , sc , f , off + f . Offset ( ) , n , nil , inList )
return next
}
}
panic ( todo ( "" , n . Position ( ) ) )
}
}
return nil
}
// Accept a single initializer, optionally enclosed in braces, but nested
// braces. Implements eg. [0]6.7.8.11.
//
// 42 // ok
// {42} // ok
// {{42}} // not ok
func ( n * Initializer ) single ( ) * Initializer {
switch n . Case {
case InitializerExpr : // AssignmentExpression
return n
case InitializerInitList : // '{' InitializerList ',' '}'
if n . InitializerList == nil { //
return nil
}
if n . InitializerList . InitializerList == nil {
if in := n . InitializerList . Initializer ; in . Case == InitializerExpr {
return in
}
}
}
return nil
}
// [0], 6.7.8 Initialization
func ( n * InitializerList ) check ( ctx * context , list * [ ] * Initializer , t Type , sc StorageClass , off uintptr , designatorList * DesignatorList , inList bool ) {
switch t . Kind ( ) {
case Array , Vector :
if n == nil { // {}
if t . IsIncomplete ( ) {
t . setLen ( 0 )
}
return
}
n . checkArray ( ctx , list , t , sc , off , designatorList , inList )
case Struct :
if n == nil { // {}
return
}
n . checkStruct ( ctx , list , t , sc , off , designatorList , inList )
case Union :
if n == nil { // {}
return
}
n . checkUnion ( ctx , list , t , sc , off , designatorList , inList )
default :
if n == nil || t == nil || t . Kind ( ) == Invalid {
return
}
n . Initializer . check ( ctx , list , t , sc , nil , off , nil , designatorList , inList )
}
}
func setLHS ( lhs map [ * Declarator ] struct { } , rhs Node ) {
inCall := 0
Inspect ( rhs , func ( n Node , enter bool ) bool {
switch x := n . ( type ) {
case * PostfixExpression :
switch x . Case {
case PostfixExpressionCall : // PostfixExpression '(' ArgumentExpressionList ')'
switch {
case enter :
inCall ++
if d := x . Declarator ( ) ; d != nil {
for v := range lhs {
d . setLHS ( v )
}
}
default :
inCall --
}
}
case * PrimaryExpression :
if inCall != 0 || ! enter {
break
}
if d := x . Declarator ( ) ; d != nil {
for v := range lhs {
d . setLHS ( v )
}
}
}
return true
} )
}
func ( n * AssignmentExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
if n . Operand != nil {
return n . Operand
}
if ctx . cfg . TrackAssignments && n . AssignmentExpression != nil {
defer func ( ) {
lhs := map [ * Declarator ] struct { } { }
Inspect ( n . UnaryExpression , func ( n Node , enter bool ) bool {
if ! enter {
return true
}
if x , ok := n . ( * PrimaryExpression ) ; ok {
lhs [ x . Declarator ( ) ] = struct { } { }
}
return true
} )
setLHS ( lhs , n . AssignmentExpression )
} ( )
}
//TODO check for "modifiable lvalue" in left operand
n . Operand = noOperand
switch n . Case {
case AssignmentExpressionCond : // ConditionalExpression
n . Operand = n . ConditionalExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ConditionalExpression . IsSideEffectsFree
case AssignmentExpressionAssign : // UnaryExpression '=' AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Declarator ( ) ; d != nil {
d . Read -= ctx . readDelta
}
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . Write ++
if l . Type ( ) . Kind ( ) == Array && ! d . IsParameter && l . Type ( ) . String ( ) != "va_list" {
ctx . errNode ( n . UnaryExpression , "assignment to expression with array type" )
break
}
}
if ! l . IsLValue ( ) {
//TODO ctx.errNode(n.UnaryExpression, "expected lvalue")
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
_ = r //TODO check assignability
n . Operand = l . ( * lvalue ) . Operand
case AssignmentExpressionMul : // UnaryExpression "*=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if l . Type ( ) . IsArithmeticType ( ) {
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionDiv : // UnaryExpression "/=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if l . Type ( ) . IsArithmeticType ( ) {
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionMod : // UnaryExpression "%=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if l . Type ( ) . IsArithmeticType ( ) {
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionAdd : // UnaryExpression "+=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
n . promote = n . UnaryExpression . Operand . Type ( )
if l . Type ( ) . IsArithmeticType ( ) {
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionSub : // UnaryExpression "-=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
n . promote = n . UnaryExpression . Operand . Type ( )
if l . Type ( ) . IsArithmeticType ( ) {
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionLsh : // UnaryExpression "<<=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if ! l . Type ( ) . IsIntegerType ( ) || ! r . Type ( ) . IsIntegerType ( ) {
//TODO report error
break
}
n . promote = r . integerPromotion ( ctx , n ) . Type ( )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) } ) . integerPromotion ( ctx , n )
case AssignmentExpressionRsh : // UnaryExpression ">>=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if ! l . Type ( ) . IsIntegerType ( ) || ! r . Type ( ) . IsIntegerType ( ) {
//TODO report error
break
}
n . promote = r . integerPromotion ( ctx , n ) . Type ( )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) } ) . integerPromotion ( ctx , n )
case AssignmentExpressionAnd : // UnaryExpression "&=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if ! l . Type ( ) . IsIntegerType ( ) || ! r . Type ( ) . IsIntegerType ( ) {
//TODO report error
break
}
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionXor : // UnaryExpression "^=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if ! l . Type ( ) . IsIntegerType ( ) || ! r . Type ( ) . IsIntegerType ( ) {
//TODO report error
break
}
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
case AssignmentExpressionOr : // UnaryExpression "|=" AssignmentExpression
l := n . UnaryExpression . check ( ctx , isAsmArg )
if d := n . UnaryExpression . Operand . Declarator ( ) ; d != nil {
d . SubjectOfAsgnOp = true
d . Read += ctx . readDelta
d . Write ++
}
if ! l . IsLValue ( ) {
//TODO panic(n.Position().String()) // report error
break
}
r := n . AssignmentExpression . check ( ctx , isAsmArg )
//TODO check assignability
if ! l . Type ( ) . IsIntegerType ( ) || ! r . Type ( ) . IsIntegerType ( ) {
//TODO report error
break
}
op , _ := usualArithmeticConversions ( ctx , n , l , r , true )
n . promote = op . Type ( )
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : l . Type ( ) }
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * UnaryExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case UnaryExpressionPostfix : // PostfixExpression
n . Operand = n . PostfixExpression . check ( ctx , false , isAsmArg )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
case UnaryExpressionInc : // "++" UnaryExpression
op := n . UnaryExpression . check ( ctx , isAsmArg )
if d := op . Declarator ( ) ; d != nil {
d . SubjectOfIncDec = true
d . Read += ctx . readDelta
d . Write ++
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
case UnaryExpressionDec : // "--" UnaryExpression
op := n . UnaryExpression . check ( ctx , isAsmArg )
if d := op . Declarator ( ) ; d != nil {
d . SubjectOfIncDec = true
d . Read += ctx . readDelta
d . Write ++
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
case UnaryExpressionAddrof : // '&' CastExpression
ctx . not ( n , mIntConstExpr )
op := n . CastExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
if op . Type ( ) . IsBitFieldType ( ) {
//TODO report error
break
}
d := n . CastExpression . Declarator ( )
if d != nil {
setAddressTaken ( n , d , "'&' CastExpression" )
if d . td . register ( ) {
//TODO report error
}
}
// [0], 6.5.3.2
//
// The operand of the unary & operator shall be either a
// function designator, the result of a [] or unary * operator,
// or an lvalue that designates an object that is not a
// bit-field and is not declared with the register
// storage-class specifier.
//TODO
if x , ok := op . ( * funcDesignator ) ; ok {
n . Operand = x
break
}
n . Operand = op
case UnaryExpressionDeref : // '*' CastExpression
ctx . not ( n , mIntConstExpr )
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
if x , ok := op . ( * funcDesignator ) ; ok {
n . Operand = x
break
}
if op . Type ( ) . Kind ( ) == Function {
n . Operand = op
break
}
if op . Type ( ) . Decay ( ) . Kind ( ) != Ptr {
//TODO report error
break
}
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) . Elem ( ) } }
case UnaryExpressionPlus : // '+' CastExpression
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
2022-11-26 23:42:16 +00:00
if op == nil {
//TODO report error
break
}
2022-01-30 23:27:37 +00:00
if ! op . Type ( ) . IsArithmeticType ( ) {
//TODO report error
break
}
if op . Type ( ) . IsIntegerType ( ) {
op = op . integerPromotion ( ctx , n )
}
n . Operand = op
case UnaryExpressionMinus : // '-' CastExpression
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
2022-11-26 23:42:16 +00:00
if op == nil {
//TODO report error
break
}
2022-01-30 23:27:37 +00:00
if op . Type ( ) . Kind ( ) == Vector {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
break
}
if ! op . Type ( ) . IsArithmeticType ( ) {
//TODO report error
break
}
if op . Type ( ) . IsIntegerType ( ) {
op = op . integerPromotion ( ctx , n )
}
if v := op . Value ( ) ; v != nil {
op = ( & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) , value : v . neg ( ) } ) . normalize ( ctx , n )
}
n . Operand = op
case UnaryExpressionCpl : // '~' CastExpression
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
if op . Type ( ) . Kind ( ) == Vector {
if ! op . Type ( ) . Elem ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operand must be integer" )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
break
}
if op . Type ( ) . IsComplexType ( ) {
n . Operand = op
break
}
if ! op . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operand must be integer" )
break
}
op = op . integerPromotion ( ctx , n )
if v := op . Value ( ) ; v != nil {
op = ( & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) , value : v . cpl ( ) } ) . normalize ( ctx , n )
}
n . Operand = op
case UnaryExpressionNot : // '!' CastExpression
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
op2 := & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) }
switch {
case op . IsZero ( ) :
op2 . value = Int64Value ( 1 )
case op . IsNonZero ( ) :
op2 . value = Int64Value ( 0 )
}
n . Operand = op2
case UnaryExpressionSizeofExpr : // "sizeof" UnaryExpression
n . IsSideEffectsFree = true
rd := ctx . readDelta
// [0]6.5.3.4, 2: If the type of the operand is a variable length array type,
// the operand is evaluated; otherwise, the operand is not evaluated and the
// result is an integer constant.
switch op := n . UnaryExpression . Operand ; {
case op != nil && op . Type ( ) != nil && op . Type ( ) . IsVLA ( ) :
ctx . readDelta = 1
default :
ctx . readDelta = 0
}
ctx . push ( ctx . mode &^ mIntConstExpr )
op := n . UnaryExpression . check ( ctx , isAsmArg )
ctx . pop ( )
ctx . readDelta = rd
if op . Type ( ) . IsIncomplete ( ) {
break
}
sz := op . Type ( ) . Size ( )
if d := n . UnaryExpression . Declarator ( ) ; d != nil && d . IsParameter {
sz = op . Type ( ) . Decay ( ) . Size ( )
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ULongLong ) , value : Uint64Value ( sz ) } ) . convertTo ( ctx , n , sizeT ( ctx , n . lexicalScope , n . Token ) )
case UnaryExpressionSizeofType : // "sizeof" '(' TypeName ')'
n . IsSideEffectsFree = true
rd := ctx . readDelta
ctx . readDelta = 0
ctx . push ( ctx . mode )
if ctx . mode & mIntConstExpr != 0 {
ctx . mode |= mIntConstExprAnyCast
}
t := n . TypeName . check ( ctx , false , false , nil )
ctx . pop ( )
ctx . readDelta = rd
if t . IsIncomplete ( ) {
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ULongLong ) , value : Uint64Value ( t . Size ( ) ) } ) . convertTo ( ctx , n , sizeT ( ctx , n . lexicalScope , n . Token ) )
case UnaryExpressionLabelAddr : // "&&" IDENTIFIER
abi := & ctx . cfg . ABI
n . Operand = & operand { abi : abi , typ : abi . Ptr ( n , abi . Type ( Void ) ) }
n . IsSideEffectsFree = true
ctx . not ( n , mIntConstExpr )
f := ctx . checkFn
if f == nil {
//TODO report error
break
}
if f . ComputedGotos == nil {
f . ComputedGotos = map [ StringID ] * UnaryExpression { }
}
f . ComputedGotos [ n . Token2 . Value ] = n
case UnaryExpressionAlignofExpr : // "_Alignof" UnaryExpression
n . IsSideEffectsFree = true
ctx . push ( ctx . mode &^ mIntConstExpr )
op := n . UnaryExpression . check ( ctx , isAsmArg )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ULongLong ) , value : Uint64Value ( op . Type ( ) . Align ( ) ) } ) . convertTo ( ctx , n , sizeT ( ctx , n . lexicalScope , n . Token ) )
ctx . pop ( )
case UnaryExpressionAlignofType : // "_Alignof" '(' TypeName ')'
n . IsSideEffectsFree = true
ctx . push ( ctx . mode )
if ctx . mode & mIntConstExpr != 0 {
ctx . mode |= mIntConstExprAnyCast
}
t := n . TypeName . check ( ctx , false , false , nil )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ULongLong ) , value : Uint64Value ( t . Align ( ) ) } ) . convertTo ( ctx , n , sizeT ( ctx , n . lexicalScope , n . Token ) )
ctx . pop ( )
case UnaryExpressionImag : // "__imag__" UnaryExpression
ctx . not ( n , mIntConstExpr )
n . UnaryExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
n . Operand = complexPart ( ctx , n . UnaryExpression . Operand )
case UnaryExpressionReal : // "__real__" UnaryExpression
ctx . not ( n , mIntConstExpr )
n . UnaryExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
n . Operand = complexPart ( ctx , n . UnaryExpression . Operand )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func complexPart ( ctx * context , op Operand ) Operand {
var k Kind
switch op . Type ( ) . Kind ( ) {
case ComplexChar :
k = Char
case ComplexDouble :
k = Double
case ComplexFloat :
k = Float
case ComplexInt :
k = Int
case ComplexLong :
k = Long
case ComplexLongDouble :
k = LongDouble
case ComplexLongLong :
k = LongLong
case ComplexShort :
k = Short
case ComplexUInt :
k = UInt
case ComplexULong :
k = ULong
case ComplexULongLong :
k = ULongLong
case ComplexUShort :
k = UShort
default :
//TODO report err
return noOperand
}
abi := & ctx . cfg . ABI
typ := abi . Type ( k )
return & operand { abi : abi , typ : typ }
}
func sizeT ( ctx * context , s Scope , tok Token ) Type {
if t := ctx . sizeT ; t != nil {
return t
}
t := ctx . stddef ( idSizeT , s , tok )
if t . Kind ( ) != Invalid {
ctx . sizeT = t
}
return t
}
func ( n * CastExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case CastExpressionUnary : // UnaryExpression
n . Operand = n . UnaryExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
case CastExpressionCast : // '(' TypeName ')' CastExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * UnaryExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case UnaryExpressionPostfix : // PostfixExpression
n . Operand = n . PostfixExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
case UnaryExpressionInc : // "++" UnaryExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionDec : // "--" UnaryExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionAddrof : // '&' CastExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionDeref : // '*' CastExpression
n . Operand = n . CastExpression . check ( ctx , false )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
case UnaryExpressionPlus : // '+' CastExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionMinus : // '-' CastExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionCpl : // '~' CastExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionNot : // '!' CastExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionSizeofExpr : // "sizeof" UnaryExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionSizeofType : // "sizeof" '(' TypeName ')'
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionLabelAddr : // "&&" IDENTIFIER
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionAlignofExpr : // "_Alignof" UnaryExpression
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionAlignofType : // "_Alignof" '(' TypeName ')'
panic ( n . Position ( ) . String ( ) )
case UnaryExpressionImag : // "__imag__" UnaryExpression
n . Operand = n . UnaryExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
case UnaryExpressionReal : // "__real__" UnaryExpression
n . Operand = n . UnaryExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * PostfixExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case PostfixExpressionPrimary : // PrimaryExpression
n . Operand = n . PrimaryExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . PrimaryExpression . IsSideEffectsFree
case PostfixExpressionIndex : // PostfixExpression '[' Expression ']'
pe := n . PostfixExpression . check ( ctx , false , false )
if d := n . PostfixExpression . Declarator ( ) ; d != nil && d . Type ( ) . Kind ( ) != Ptr {
setAddressTaken ( n , d , "PostfixExpression '[' Expression ']'" )
d . Read += ctx . readDelta
}
e := n . Expression . check ( ctx , false )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree && n . Expression . IsSideEffectsFree
t := pe . Type ( ) . Decay ( )
if t . Kind ( ) == Invalid {
break
}
if t . Kind ( ) == Ptr {
if t := e . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , e . Type ( ) )
break
}
n . Operand = n . indexAddr ( ctx , & n . Token , pe , e )
break
}
if pe . Type ( ) . Kind ( ) == Vector {
if t := e . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , e . Type ( ) )
break
}
n . Operand = n . index ( ctx , pe , e )
break
}
t = e . Type ( ) . Decay ( )
if t . Kind ( ) == Invalid {
break
}
if t . Kind ( ) == Ptr {
if t := pe . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , pe . Type ( ) )
break
}
n . Operand = n . indexAddr ( ctx , & n . Token , e , pe )
break
}
ctx . errNode ( n , "invalid index expression %v[%v]" , pe . Type ( ) , e . Type ( ) )
case PostfixExpressionCall : // PostfixExpression '(' ArgumentExpressionList ')'
panic ( n . Position ( ) . String ( ) )
case PostfixExpressionSelect : // PostfixExpression '.' IDENTIFIER
op := n . PostfixExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
if d := n . PostfixExpression . Declarator ( ) ; d != nil {
setAddressTaken ( n , d , "PostfixExpression '.' IDENTIFIER" )
d . Read += ctx . readDelta
}
st := op . Type ( ) . Elem ( )
if k := st . Kind ( ) ; k == Invalid || k != Struct && k != Union {
//TODO report error
break
}
f , ok := st . FieldByName ( n . Token2 . Value )
if ! ok {
ctx . errNode ( & n . Token2 , "unknown or ambiguous field: %s" , n . Token2 . Value )
break
}
n . Field = f
ft := f . Type ( )
if f . IsBitField ( ) {
//TODO report error
break
}
ot := ctx . cfg . ABI . Ptr ( n , ft )
switch {
case op . IsConst ( ) :
switch x := op . Value ( ) . ( type ) {
case Uint64Value :
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ot , value : x + Uint64Value ( f . Offset ( ) ) }
return n . Operand
case nil :
// nop
default :
//TODO panic(todo(" %v: %T", n.Position(), x))
}
fallthrough
default :
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ot , offset : op . Offset ( ) + f . Offset ( ) } , declarator : op . Declarator ( ) }
}
case PostfixExpressionPSelect : // PostfixExpression "->" IDENTIFIER
op := n . PostfixExpression . check ( ctx , false , false )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
if d := n . PostfixExpression . Declarator ( ) ; d != nil {
d . Read += ctx . readDelta
}
t := op . Type ( )
if k := t . Decay ( ) . Kind ( ) ; k == Invalid || k != Ptr {
//TODO report error
break
}
st := t . Elem ( )
if k := st . Kind ( ) ; k == Invalid || k != Struct && k != Union {
//TODO report error
break
}
f , ok := st . FieldByName ( n . Token2 . Value )
if ! ok {
//TODO report error
break
}
n . Field = f
ft := f . Type ( )
if f . IsBitField ( ) {
//TODO report error
break
}
ot := ctx . cfg . ABI . Ptr ( n , ft )
switch {
case op . IsConst ( ) :
switch x := op . Value ( ) . ( type ) {
case Uint64Value :
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ot , value : x + Uint64Value ( f . Offset ( ) ) }
return n . Operand
case nil :
// nop
default :
panic ( todo ( " %T" , x ) )
}
fallthrough
default :
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ot , offset : op . Offset ( ) + f . Offset ( ) } , declarator : op . Declarator ( ) }
}
case PostfixExpressionInc : // PostfixExpression "++"
panic ( n . Position ( ) . String ( ) )
case PostfixExpressionDec : // PostfixExpression "--"
panic ( n . Position ( ) . String ( ) )
case PostfixExpressionComplit : // '(' TypeName ')' '{' InitializerList ',' '}'
//TODO IsSideEffectsFree
if f := ctx . checkFn ; f != nil {
f . CompositeLiterals = append ( f . CompositeLiterals , n )
}
t := n . TypeName . check ( ctx , false , false , nil )
var v * InitializerValue
if n . InitializerList != nil {
n . InitializerList . isConst = true
n . InitializerList . check ( ctx , & n . InitializerList . list , t , Automatic , 0 , nil , false )
n . InitializerList . setConstZero ( )
v = & InitializerValue { typ : ctx . cfg . ABI . Ptr ( n , t ) , initializer : n . InitializerList }
}
n . Operand = & lvalue { Operand : ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , t ) , value : v } ) . normalize ( ctx , n ) }
case PostfixExpressionTypeCmp : // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * PostfixExpression ) indexAddr ( ctx * context , nd Node , pe , e Operand ) Operand {
var x uintptr
hasx := false
switch v := e . Value ( ) . ( type ) {
case Int64Value :
x = uintptr ( v )
hasx = true
case Uint64Value :
x = uintptr ( v )
hasx = true
}
off := x * pe . Type ( ) . Elem ( ) . Size ( )
switch y := pe . Value ( ) . ( type ) {
case StringValue , WideStringValue :
if hasx {
return & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , pe . Type ( ) . Elem ( ) ) , value : pe . Value ( ) , offset : off } }
}
case Uint64Value :
if hasx {
return & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , pe . Type ( ) . Elem ( ) ) , value : y + Uint64Value ( off ) } }
}
}
if d := pe . Declarator ( ) ; d != nil && hasx {
r := & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , pe . Type ( ) . Elem ( ) ) , offset : pe . Offset ( ) + off } , declarator : d }
return r
}
return & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , pe . Type ( ) . Elem ( ) ) } }
}
func ( n * PrimaryExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case PrimaryExpressionIdent : // IDENTIFIER
n . IsSideEffectsFree = true
n . check ( ctx , false , false )
if d := n . Operand . Declarator ( ) ; d != nil {
switch d . Type ( ) . Kind ( ) {
case Function :
// nop //TODO ?
default :
setAddressTaken ( n , d , "&IDENTIFIER" )
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , d . Type ( ) ) } , declarator : d }
}
return n . Operand
}
if ctx . cfg . RejectLateBinding && ! ctx . cfg . ignoreUndefinedIdentifiers {
ctx . errNode ( n , "front-end: undefined: %s" , n . Token . Value )
return noOperand
}
//TODO
case PrimaryExpressionInt : // INTCONST
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionFloat : // FLOATCONST
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionEnum : // ENUMCONST
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionChar : // CHARCONST
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionLChar : // LONGCHARCONST
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionString : // STRINGLITERAL
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionLString : // LONGSTRINGLITERAL
panic ( n . Position ( ) . String ( ) )
case PrimaryExpressionExpr : // '(' Expression ')'
n . Operand = n . Expression . addrOf ( ctx )
n . IsSideEffectsFree = n . Expression . IsSideEffectsFree
case PrimaryExpressionStmt : // '(' CompoundStatement ')'
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * Expression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ExpressionAssign : // AssignmentExpression
n . Operand = n . AssignmentExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . AssignmentExpression . IsSideEffectsFree
case ExpressionComma : // Expression ',' AssignmentExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * AssignmentExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case AssignmentExpressionCond : // ConditionalExpression
n . Operand = n . ConditionalExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . ConditionalExpression . IsSideEffectsFree
case AssignmentExpressionAssign : // UnaryExpression '=' AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionMul : // UnaryExpression "*=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionDiv : // UnaryExpression "/=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionMod : // UnaryExpression "%=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionAdd : // UnaryExpression "+=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionSub : // UnaryExpression "-=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionLsh : // UnaryExpression "<<=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionRsh : // UnaryExpression ">>=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionAnd : // UnaryExpression "&=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionXor : // UnaryExpression "^=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
case AssignmentExpressionOr : // UnaryExpression "|=" AssignmentExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * ConditionalExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ConditionalExpressionLOr : // LogicalOrExpression
n . Operand = n . LogicalOrExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree
case ConditionalExpressionCond : // LogicalOrExpression '?' Expression ':' ConditionalExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * LogicalOrExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case LogicalOrExpressionLAnd : // LogicalAndExpression
n . Operand = n . LogicalAndExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . LogicalAndExpression . IsSideEffectsFree
case LogicalOrExpressionLOr : // LogicalOrExpression "||" LogicalAndExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * LogicalAndExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case LogicalAndExpressionOr : // InclusiveOrExpression
n . Operand = n . InclusiveOrExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . InclusiveOrExpression . IsSideEffectsFree
case LogicalAndExpressionLAnd : // LogicalAndExpression "&&" InclusiveOrExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * InclusiveOrExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case InclusiveOrExpressionXor : // ExclusiveOrExpression
n . Operand = n . ExclusiveOrExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . ExclusiveOrExpression . IsSideEffectsFree
case InclusiveOrExpressionOr : // InclusiveOrExpression '|' ExclusiveOrExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * ExclusiveOrExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ExclusiveOrExpressionAnd : // AndExpression
n . Operand = n . AndExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . AndExpression . IsSideEffectsFree
case ExclusiveOrExpressionXor : // ExclusiveOrExpression '^' AndExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * AndExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case AndExpressionEq : // EqualityExpression
n . Operand = n . EqualityExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . EqualityExpression . IsSideEffectsFree
case AndExpressionAnd : // AndExpression '&' EqualityExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * EqualityExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case EqualityExpressionRel : // RelationalExpression
n . Operand = n . RelationalExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . RelationalExpression . IsSideEffectsFree
case EqualityExpressionEq : // EqualityExpression "==" RelationalExpression
panic ( n . Position ( ) . String ( ) )
case EqualityExpressionNeq : // EqualityExpression "!=" RelationalExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * RelationalExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case RelationalExpressionShift : // ShiftExpression
n . Operand = n . ShiftExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . ShiftExpression . IsSideEffectsFree
case RelationalExpressionLt : // RelationalExpression '<' ShiftExpression
panic ( n . Position ( ) . String ( ) )
case RelationalExpressionGt : // RelationalExpression '>' ShiftExpression
panic ( n . Position ( ) . String ( ) )
case RelationalExpressionLeq : // RelationalExpression "<=" ShiftExpression
panic ( n . Position ( ) . String ( ) )
case RelationalExpressionGeq : // RelationalExpression ">=" ShiftExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * ShiftExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ShiftExpressionAdd : // AdditiveExpression
n . Operand = n . AdditiveExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . AdditiveExpression . IsSideEffectsFree
case ShiftExpressionLsh : // ShiftExpression "<<" AdditiveExpression
panic ( n . Position ( ) . String ( ) )
case ShiftExpressionRsh : // ShiftExpression ">>" AdditiveExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * AdditiveExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case AdditiveExpressionMul : // MultiplicativeExpression
n . Operand = n . MultiplicativeExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . MultiplicativeExpression . IsSideEffectsFree
case AdditiveExpressionAdd : // AdditiveExpression '+' MultiplicativeExpression
panic ( n . Position ( ) . String ( ) )
case AdditiveExpressionSub : // AdditiveExpression '-' MultiplicativeExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * MultiplicativeExpression ) addrOf ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case MultiplicativeExpressionCast : // CastExpression
n . Operand = n . CastExpression . addrOf ( ctx )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
case MultiplicativeExpressionMul : // MultiplicativeExpression '*' CastExpression
panic ( n . Position ( ) . String ( ) )
case MultiplicativeExpressionDiv : // MultiplicativeExpression '/' CastExpression
panic ( n . Position ( ) . String ( ) )
case MultiplicativeExpressionMod : // MultiplicativeExpression '%' CastExpression
panic ( n . Position ( ) . String ( ) )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * TypeName ) check ( ctx * context , inUnion , isPacked bool , list * [ ] * TypeSpecifier ) Type {
if n == nil {
return noType
}
n . typ = n . SpecifierQualifierList . check ( ctx , inUnion , isPacked , list )
if n . AbstractDeclarator != nil {
n . typ = n . AbstractDeclarator . check ( ctx , n . typ )
}
for list := n . SpecifierQualifierList ; list != nil ; list = list . SpecifierQualifierList {
if expr , ok := list . AttributeSpecifier . Has ( idVectorSize , idVectorSize2 ) ; ok {
n . vectorize ( ctx , expr )
break
}
}
return n . typ
}
func ( n * TypeName ) vectorize ( ctx * context , expr * ExpressionList ) {
dst := & n . typ
elem := n . typ
switch n . typ . Kind ( ) {
case Function :
dst = & n . typ . ( * functionType ) . result
elem = n . typ . Result ( )
}
sz := expr . vectorSize ( ctx )
if sz == 0 {
sz = elem . Size ( )
}
if sz % elem . Size ( ) != 0 {
ctx . errNode ( expr , "vector size must be a multiple of the base size" )
}
b := n . typ . base ( )
b . size = sz
b . kind = byte ( Vector )
* dst = & vectorType {
typeBase : b ,
elem : elem ,
length : sz / elem . Size ( ) ,
}
}
func ( n * AbstractDeclarator ) check ( ctx * context , typ Type ) Type {
if n == nil {
return typ
}
n . typ = noType //TODO-
switch n . Case {
case AbstractDeclaratorPtr : // Pointer
n . typ = n . Pointer . check ( ctx , typ )
case AbstractDeclaratorDecl : // Pointer DirectAbstractDeclarator
typ = n . Pointer . check ( ctx , typ )
n . typ = n . DirectAbstractDeclarator . check ( ctx , typ )
default :
panic ( todo ( "" ) )
}
return n . typ
}
func ( n * DirectAbstractDeclarator ) check ( ctx * context , typ Type ) Type {
if n == nil {
return typ
}
switch n . Case {
case DirectAbstractDeclaratorDecl : // '(' AbstractDeclarator ')'
if n . AbstractDeclarator == nil {
// [0], 6.7.6, 128)
//
// As indicated by the syntax, empty parentheses in a
// type name are interpreted as ‘ ‘ function with no
// parameter specification’ ’ , rather than redundant
// parentheses around the omitted identifier.
panic ( todo ( "" ) ) //TODO
}
return n . AbstractDeclarator . check ( ctx , typ )
case DirectAbstractDeclaratorArr : // DirectAbstractDeclarator '[' TypeQualifiers AssignmentExpression ']'
return n . DirectAbstractDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , true , false ) )
case DirectAbstractDeclaratorStaticArr : // DirectAbstractDeclarator '[' "static" TypeQualifiers AssignmentExpression ']'
return n . DirectAbstractDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , false , false ) )
case DirectAbstractDeclaratorArrStatic : // DirectAbstractDeclarator '[' TypeQualifiers "static" AssignmentExpression ']'
return n . DirectAbstractDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , false , false ) )
case DirectAbstractDeclaratorArrStar : // DirectAbstractDeclarator '[' '*' ']'
return n . DirectAbstractDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , nil , true , true ) )
case DirectAbstractDeclaratorFunc : // DirectAbstractDeclarator '(' ParameterTypeList ')'
ft := & functionType { typeBase : typeBase { kind : byte ( Function ) } , result : typ }
n . ParameterTypeList . check ( ctx , ft )
return n . DirectAbstractDeclarator . check ( ctx , ft )
}
panic ( internalErrorf ( "%v: %v" , n . Position ( ) , n . Case ) )
}
func ( n * ParameterTypeList ) check ( ctx * context , ft * functionType ) {
if n == nil {
return
}
switch n . Case {
case ParameterTypeListList : // ParameterList
n . ParameterList . check ( ctx , ft )
case ParameterTypeListVar : // ParameterList ',' "..."
ft . variadic = true
n . ParameterList . check ( ctx , ft )
default :
panic ( todo ( "" ) )
}
}
func ( n * ParameterList ) check ( ctx * context , ft * functionType ) {
for ; n != nil ; n = n . ParameterList {
p := n . ParameterDeclaration . check ( ctx , ft )
ft . params = append ( ft . params , p )
}
}
func ( n * ParameterDeclaration ) check ( ctx * context , ft * functionType ) * Parameter {
if n == nil {
return nil
}
switch n . Case {
case ParameterDeclarationDecl : // DeclarationSpecifiers Declarator AttributeSpecifierList
typ , _ , _ := n . DeclarationSpecifiers . check ( ctx , false )
n . Declarator . IsParameter = true
if n . typ = n . Declarator . check ( ctx , n . DeclarationSpecifiers , typ , false ) ; n . typ . Kind ( ) == Void {
panic ( n . Position ( ) . String ( ) )
}
if n . AttributeSpecifierList != nil {
//TODO panic(n.Position().String())
}
n . AttributeSpecifierList . check ( ctx , n . typ . baseP ( ) )
return & Parameter { d : n . Declarator , typ : n . typ }
case ParameterDeclarationAbstract : // DeclarationSpecifiers AbstractDeclarator
n . typ , _ , _ = n . DeclarationSpecifiers . check ( ctx , false )
if n . AbstractDeclarator != nil {
n . typ = n . AbstractDeclarator . check ( ctx , n . typ )
}
return & Parameter { typ : n . typ }
default :
panic ( todo ( "" ) )
}
}
func ( n * Pointer ) check ( ctx * context , typ Type ) ( t Type ) {
if n == nil || typ == nil {
return typ
}
switch n . Case {
case PointerTypeQual : // '*' TypeQualifiers
n . TypeQualifiers . check ( ctx , & n . typeQualifiers )
case PointerPtr : // '*' TypeQualifiers Pointer
n . TypeQualifiers . check ( ctx , & n . typeQualifiers )
typ = n . Pointer . check ( ctx , typ )
case PointerBlock : // '^' TypeQualifiers
n . TypeQualifiers . check ( ctx , & n . typeQualifiers )
default :
panic ( todo ( "" ) )
}
r := ctx . cfg . ABI . Ptr ( n , typ ) . ( * pointerType )
if n . typeQualifiers != nil {
r . typeQualifiers = n . typeQualifiers . check ( ctx , ( * DeclarationSpecifiers ) ( nil ) , false )
}
return r
}
func ( n * TypeQualifiers ) check ( ctx * context , typ * * typeBase ) {
for ; n != nil ; n = n . TypeQualifiers {
switch n . Case {
case TypeQualifiersTypeQual : // TypeQualifier
if * typ == nil {
* typ = & typeBase { }
}
n . TypeQualifier . check ( ctx , * typ )
case TypeQualifiersAttribute : // AttributeSpecifier
if * typ == nil {
* typ = & typeBase { }
}
n . AttributeSpecifier . check ( ctx , * typ )
default :
panic ( todo ( "" ) )
}
}
}
func ( n * TypeQualifier ) check ( ctx * context , typ * typeBase ) {
if n == nil {
return
}
switch n . Case {
case TypeQualifierConst : // "const"
typ . flags |= fConst
case TypeQualifierRestrict : // "restrict"
typ . flags |= fRestrict
case TypeQualifierVolatile : // "volatile"
typ . flags |= fVolatile
case TypeQualifierAtomic : // "_Atomic"
typ . flags |= fAtomic
default :
panic ( todo ( "" ) )
}
}
func ( n * SpecifierQualifierList ) check ( ctx * context , inUnion , isPacked bool , list * [ ] * TypeSpecifier ) Type {
n0 := n
typ := & typeBase { }
for ; n != nil ; n = n . SpecifierQualifierList {
switch n . Case {
case SpecifierQualifierListTypeSpec : // TypeSpecifier SpecifierQualifierList
n . TypeSpecifier . check ( ctx , typ , inUnion )
if list != nil && n . TypeSpecifier . Case != TypeSpecifierAtomic {
* list = append ( * list , n . TypeSpecifier )
}
case SpecifierQualifierListTypeQual : // TypeQualifier SpecifierQualifierList
n . TypeQualifier . check ( ctx , typ )
case SpecifierQualifierListAlignSpec : // AlignmentSpecifier SpecifierQualifierList
n . AlignmentSpecifier . check ( ctx )
case SpecifierQualifierListAttribute : // AttributeSpecifier SpecifierQualifierList
n . AttributeSpecifier . check ( ctx , typ )
default :
panic ( todo ( "" ) )
}
}
return typ . check ( ctx , n0 , true )
}
func ( n * TypeSpecifier ) check ( ctx * context , typ * typeBase , inUnion bool ) {
if n == nil {
return
}
switch n . Case {
case
TypeSpecifierVoid , // "void"
TypeSpecifierChar , // "char"
TypeSpecifierShort , // "short"
TypeSpecifierInt , // "int"
TypeSpecifierInt8 , // "__int8"
TypeSpecifierInt16 , // "__int16"
TypeSpecifierInt32 , // "__int32"
TypeSpecifierInt64 , // "__int64"
TypeSpecifierInt128 , // "__int128"
TypeSpecifierLong , // "long"
TypeSpecifierFloat , // "float"
TypeSpecifierFloat16 , // "__fp16"
TypeSpecifierDecimal32 , // "_Decimal32"
TypeSpecifierDecimal64 , // "_Decimal64"
TypeSpecifierDecimal128 , // "_Decimal128"
TypeSpecifierFloat32 , // "_Float32"
TypeSpecifierFloat32x , // "_Float32x"
TypeSpecifierFloat64 , // "_Float64"
TypeSpecifierFloat64x , // "_Float64x"
TypeSpecifierFloat128 , // "_Float128"
TypeSpecifierFloat80 , // "__float80"
TypeSpecifierDouble , // "double"
TypeSpecifierSigned , // "signed"
TypeSpecifierUnsigned , // "unsigned"
TypeSpecifierBool , // "_Bool"
TypeSpecifierComplex : // "_Complex"
// nop
case TypeSpecifierStructOrUnion : // StructOrUnionSpecifier
n . StructOrUnionSpecifier . check ( ctx , typ , inUnion )
case TypeSpecifierEnum : // EnumSpecifier
n . EnumSpecifier . check ( ctx )
case TypeSpecifierTypedefName : // TYPEDEFNAME
// nop
case TypeSpecifierTypeofExpr : // "typeof" '(' Expression ')'
op := n . Expression . check ( ctx , false )
n . typ = op . Type ( )
case TypeSpecifierTypeofType : // "typeof" '(' TypeName ')'
n . typ = n . TypeName . check ( ctx , false , false , nil )
case TypeSpecifierAtomic : // AtomicTypeSpecifier
t := n . AtomicTypeSpecifier . check ( ctx )
typ . kind = t . base ( ) . kind
typ . flags |= fAtomic
n . typ = typ
case
TypeSpecifierFract , // "_Fract"
TypeSpecifierSat , // "_Sat"
TypeSpecifierAccum : // "_Accum"
// nop
default :
panic ( todo ( "" ) )
}
}
func ( n * AtomicTypeSpecifier ) check ( ctx * context ) Type {
if n == nil {
return nil
}
return n . TypeName . check ( ctx , false , false , & n . list )
}
func ( n * EnumSpecifier ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case EnumSpecifierDef : // "enum" AttributeSpecifierList IDENTIFIER '{' EnumeratorList ',' '}'
n . AttributeSpecifierList . check ( ctx , nil )
min , max := n . EnumeratorList . check ( ctx )
var tmin , tmax Type
switch min := min . ( type ) {
case Int64Value :
switch {
case min >= 0 && ctx . cfg . UnsignedEnums :
tmin = n . requireUint ( ctx , uint64 ( min ) )
switch max := max . ( type ) {
case Int64Value :
tmax = n . requireUint ( ctx , uint64 ( max ) )
case Uint64Value :
tmax = n . requireUint ( ctx , uint64 ( max ) )
case nil :
panic ( todo ( "%v:" , n . Position ( ) ) )
}
default :
tmin = n . requireInt ( ctx , int64 ( min ) )
switch max := max . ( type ) {
case Int64Value :
tmax = n . requireInt ( ctx , int64 ( max ) )
case Uint64Value :
tmax = n . requireInt ( ctx , int64 ( max ) )
case nil :
panic ( todo ( "%v:" , n . Position ( ) ) )
}
}
case Uint64Value :
tmin = n . requireUint ( ctx , uint64 ( min ) )
switch max := max . ( type ) {
case Int64Value :
if max < 0 {
panic ( todo ( "%v: min %v max %v" , n . Position ( ) , min , max ) )
}
tmax = n . requireUint ( ctx , uint64 ( max ) )
case Uint64Value :
tmax = n . requireUint ( ctx , uint64 ( max ) )
case nil :
_ = max
panic ( todo ( "%v:" , n . Position ( ) ) )
}
case nil :
panic ( todo ( "%v: %v %T" , n . Position ( ) , n . Case , min ) )
}
switch {
case tmin . Size ( ) > tmax . Size ( ) :
n . typ = tmin
default :
n . typ = tmax
}
if ! n . typ . IsIntegerType ( ) || n . typ . Size ( ) == 0 { //TODO-
panic ( todo ( "" ) )
}
reg := n . lexicalScope . Parent ( ) == nil
for list := n . EnumeratorList ; list != nil ; list = list . EnumeratorList {
en := list . Enumerator
en . Operand = en . Operand . convertTo ( ctx , en , n . typ )
if reg {
ctx . enums [ en . Token . Value ] = en . Operand
}
}
case EnumSpecifierTag : // "enum" AttributeSpecifierList IDENTIFIER
n . typ = & taggedType {
resolutionScope : n . lexicalScope ,
tag : n . Token2 . Value ,
typeBase : & typeBase { kind : byte ( Enum ) } ,
}
default :
panic ( todo ( "" ) )
}
}
func ( n * EnumSpecifier ) requireInt ( ctx * context , m int64 ) ( r Type ) {
var w int
switch {
case m < 0 :
w = mathutil . BitLenUint64 ( uint64 ( - m ) )
default :
w = mathutil . BitLenUint64 ( uint64 ( m ) ) + 1
}
w = mathutil . Max ( w , 32 )
abi := ctx . cfg . ABI
for k0 , v := range intConvRank {
k := Kind ( k0 )
if k == Bool || k == Enum || v == 0 || ! abi . isSignedInteger ( k ) {
continue
}
t := abi . Types [ k ]
if int ( t . Size ) * 8 < w {
continue
}
if r == nil || t . Size < r . Size ( ) {
r = abi . Type ( k )
}
}
if r == nil || r . Size ( ) == 0 { //TODO-
panic ( todo ( "" ) )
}
return r
}
func ( n * EnumSpecifier ) requireUint ( ctx * context , m uint64 ) ( r Type ) {
w := mathutil . BitLenUint64 ( m )
w = mathutil . Max ( w , 32 )
abi := ctx . cfg . ABI
for k0 , v := range intConvRank {
k := Kind ( k0 )
if k == Bool || k == Enum || v == 0 || abi . isSignedInteger ( k ) {
continue
}
t := abi . Types [ k ]
if int ( t . Size ) * 8 < w {
continue
}
if r == nil || t . Size < r . Size ( ) {
r = abi . Type ( k )
}
}
if r == nil || r . Size ( ) == 0 { //TODO-
panic ( todo ( "" ) )
}
return r
}
func ( n * EnumeratorList ) check ( ctx * context ) ( min , max Value ) {
var iota Value
for ; n != nil ; n = n . EnumeratorList {
iota , min , max = n . Enumerator . check ( ctx , iota , min , max )
}
return min , max
}
func ( n * Enumerator ) check ( ctx * context , iota , min , max Value ) ( Value , Value , Value ) {
if n == nil {
return nil , nil , nil
}
if iota == nil {
iota = Int64Value ( 0 )
}
switch n . Case {
case EnumeratorIdent : // IDENTIFIER AttributeSpecifierList
n . AttributeSpecifierList . check ( ctx , nil )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : iota } ) . normalize ( ctx , n )
case EnumeratorExpr : // IDENTIFIER AttributeSpecifierList '=' ConstantExpression
n . AttributeSpecifierList . check ( ctx , nil )
n . Operand = n . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false )
iota = n . Operand . Value ( )
default :
panic ( todo ( "" ) )
}
switch x := iota . ( type ) {
case Int64Value :
switch m := min . ( type ) {
case Int64Value :
if x < m {
min = x
}
case Uint64Value :
if x < 0 || Uint64Value ( x ) < m {
min = x
}
case nil :
min = x
}
switch m := max . ( type ) {
case Int64Value :
if x > m {
max = x
}
case Uint64Value :
if x >= 0 && Uint64Value ( x ) > m {
max = x
}
case nil :
max = x
}
x ++
iota = x
case Uint64Value :
switch m := min . ( type ) {
case Int64Value :
if m < 0 {
break
}
if x < Uint64Value ( m ) {
min = x
}
case Uint64Value :
if x < m {
min = x
}
case nil :
min = x
}
switch m := max . ( type ) {
case Int64Value :
if m < 0 {
max = x
break
}
if x > Uint64Value ( m ) {
max = x
}
case Uint64Value :
if x > m {
max = x
}
case nil :
max = x
}
x ++
iota = x
case nil :
//TODO report type
}
return iota , min , max
}
func ( n * ConstantExpression ) check ( ctx * context , mode mode , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
ctx . push ( mode )
n . Operand = n . ConditionalExpression . check ( ctx , isAsmArg )
ctx . pop ( )
return n . Operand
}
func ( n * StructOrUnionSpecifier ) check ( ctx * context , typ * typeBase , inUnion bool ) Type {
if n == nil {
return noType
}
switch n . Case {
case StructOrUnionSpecifierDef : // StructOrUnion AttributeSpecifierList IDENTIFIER '{' StructDeclarationList '}'
typ . kind = byte ( n . StructOrUnion . check ( ctx ) )
attr := n . AttributeSpecifierList . check ( ctx , typ )
fields := n . StructDeclarationList . check ( ctx , inUnion || typ . Kind ( ) == Union , typ . IsPacked ( ) )
m := make ( map [ StringID ] * field , len ( fields ) )
x := 0
for _ , v := range fields {
if v . name != 0 {
v . x = x
v . xs = [ ] int { x }
x ++
m [ v . name ] = v
}
}
t := ( & structType {
attr : attr ,
fields : fields ,
m : m ,
tag : n . Token . Value ,
typeBase : typ ,
} ) . check ( ctx , n )
if typ . Kind ( ) == Union {
var k Kind
for _ , v := range fields {
if k == Invalid {
k = v . typ . Kind ( )
continue
}
if v . typ . Kind ( ) != k {
k = Invalid
break
}
}
t . common = k
}
n . typ = t
if nm := n . Token . Value ; nm != 0 && n . lexicalScope . Parent ( ) == nil {
ctx . structTypes [ nm ] = t
}
case StructOrUnionSpecifierTag : // StructOrUnion AttributeSpecifierList IDENTIFIER
typ . kind = byte ( n . StructOrUnion . check ( ctx ) )
attr := n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) )
n . typ = & taggedType {
resolutionScope : n . lexicalScope ,
tag : n . Token . Value ,
typeBase : typ ,
}
if attr != nil {
n . typ = & attributedType { n . typ , attr }
}
default :
panic ( todo ( "" ) )
}
return n . typ
}
func ( n * StructDeclarationList ) check ( ctx * context , inUnion , isPacked bool ) ( s [ ] * field ) {
for ; n != nil ; n = n . StructDeclarationList {
s = append ( s , n . StructDeclaration . check ( ctx , inUnion , isPacked ) ... )
}
return s
}
func ( n * StructDeclaration ) check ( ctx * context , inUnion , isPacked bool ) ( s [ ] * field ) {
if n == nil || n . Empty {
return nil
}
typ := n . SpecifierQualifierList . check ( ctx , inUnion , isPacked , nil )
if n . StructDeclaratorList != nil {
return n . StructDeclaratorList . check ( ctx , n . SpecifierQualifierList , typ , inUnion , isPacked )
}
return [ ] * field { { typ : typ , inUnion : inUnion } }
}
func ( n * StructDeclaratorList ) check ( ctx * context , td typeDescriptor , typ Type , inUnion , isPacked bool ) ( s [ ] * field ) {
for ; n != nil ; n = n . StructDeclaratorList {
s = append ( s , n . StructDeclarator . check ( ctx , td , typ , inUnion , isPacked ) )
}
return s
}
func ( n * StructDeclarator ) check ( ctx * context , td typeDescriptor , typ Type , inUnion , isPacked bool ) * field {
if n == nil {
return nil
}
if isPacked {
typ . baseP ( ) . flags |= fPacked
}
if n . Declarator != nil {
typ = n . Declarator . check ( ctx , td , typ , false )
}
if attr := n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) ) ; len ( attr ) != 0 {
typ = & attributedType { typ , attr }
}
sf := & field {
typ : typ ,
d : n ,
inUnion : inUnion ,
}
switch n . Case {
case StructDeclaratorDecl : // Declarator
sf . name = n . Declarator . Name ( )
case StructDeclaratorBitField : // Declarator ':' ConstantExpression AttributeSpecifierList
sf . isBitField = true
sf . typ = & bitFieldType { Type : typ , field : sf }
sf . name = n . Declarator . Name ( )
if op := n . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false ) ; op . Type ( ) . IsIntegerType ( ) {
switch x := op . Value ( ) . ( type ) {
case Int64Value :
if x < 0 || x > 64 {
panic ( "TODO" )
}
sf . bitFieldWidth = byte ( x )
case Uint64Value :
if x > 64 {
panic ( "TODO" )
}
sf . bitFieldWidth = byte ( x )
default :
//dbg("%T", x)
panic ( PrettyString ( op ) )
}
} else {
//dbg("", n.ConstantExpression)
panic ( n . Declarator . Position ( ) )
}
n . AttributeSpecifierList . check ( ctx , sf . typ . baseP ( ) )
default :
panic ( todo ( "" ) )
}
return sf
}
func ( n * StructOrUnion ) check ( ctx * context ) Kind {
if n == nil {
return Invalid
}
switch n . Case {
case StructOrUnionStruct : // "struct"
return Struct
case StructOrUnionUnion : // "union"
return Union
default :
panic ( todo ( "" ) )
}
}
func ( n * CastExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case CastExpressionUnary : // UnaryExpression
n . Operand = n . UnaryExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . UnaryExpression . IsSideEffectsFree
case CastExpressionCast : // '(' TypeName ')' CastExpression
t := n . TypeName . check ( ctx , false , false , nil )
ctx . push ( ctx . mode )
if m := ctx . mode ; m & mIntConstExpr != 0 && m & mIntConstExprAnyCast == 0 {
if t := n . TypeName . Type ( ) ; t != nil && t . Kind ( ) != Int {
ctx . mode &^= mIntConstExpr
}
ctx . mode |= mIntConstExprFloat
}
op := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
ctx . pop ( )
n . Operand = op . convertTo ( ctx , n , t )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * PostfixExpression ) check ( ctx * context , implicitFunc , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
out :
switch n . Case {
case PostfixExpressionPrimary : // PrimaryExpression
n . Operand = n . PrimaryExpression . check ( ctx , implicitFunc , isAsmArg )
n . IsSideEffectsFree = n . PrimaryExpression . IsSideEffectsFree
case PostfixExpressionIndex : // PostfixExpression '[' Expression ']'
pe := n . PostfixExpression . check ( ctx , false , isAsmArg )
if d := pe . Declarator ( ) ; d != nil {
d . Read += ctx . readDelta
}
e := n . Expression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree && n . Expression . IsSideEffectsFree
t := pe . Type ( ) . Decay ( )
if t . Kind ( ) == Invalid {
break
}
if t . Kind ( ) == Ptr {
if t := e . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , e . Type ( ) )
break
}
n . Operand = n . index ( ctx , pe , e )
break
}
if pe . Type ( ) . Kind ( ) == Vector {
if t := e . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , e . Type ( ) )
break
}
n . Operand = n . index ( ctx , pe , e )
break
}
t = e . Type ( ) . Decay ( )
if t . Kind ( ) == Invalid {
break
}
if t . Kind ( ) == Ptr {
if t := pe . Type ( ) ; t . Kind ( ) != Invalid && ! t . IsIntegerType ( ) {
ctx . errNode ( n . Expression , "index must be integer type, have %v" , pe . Type ( ) )
break
}
n . Operand = n . index ( ctx , e , pe )
break
}
ctx . errNode ( n , "invalid index expression %v[%v]" , pe . Type ( ) , e . Type ( ) )
case PostfixExpressionCall : // PostfixExpression '(' ArgumentExpressionList ')'
op := n . PostfixExpression . check ( ctx , true , isAsmArg )
Inspect ( n . PostfixExpression , func ( n Node , enter bool ) bool {
if ! enter {
return true
}
if x , ok := n . ( * PrimaryExpression ) ; ok {
if d := x . Declarator ( ) ; d != nil {
d . called = true
}
}
return true
} )
args := n . ArgumentExpressionList . check ( ctx , n . PostfixExpression . Declarator ( ) , isAsmArg )
switch op . Declarator ( ) . Name ( ) {
case idBuiltinConstantPImpl :
if len ( args ) < 2 {
panic ( todo ( "" ) )
}
var v Int64Value
if args [ 1 ] . Value ( ) != nil {
v = 1
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : v }
default :
switch n . PostfixExpression . Operand . Value ( ) . ( type ) {
case StringValue , WideStringValue :
if isAsmArg {
// asm("foo": "bar" (a))
// ^
break out
}
}
n . Operand = n . checkCall ( ctx , n , op . Type ( ) , args , n . ArgumentExpressionList )
}
case PostfixExpressionSelect : // PostfixExpression '.' IDENTIFIER
op := n . PostfixExpression . check ( ctx , false , isAsmArg )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
if d := op . Declarator ( ) ; d != nil {
d . Read += ctx . readDelta
}
st := op . Type ( )
st0 := st . underlyingType ( )
if k := st . Kind ( ) ; k == Invalid || k != Struct && k != Union {
ctx . errNode ( n . PostfixExpression , "select expression of wrong type: %s (%s)" , st , st0 )
break
}
f , ok := st . FieldByName ( n . Token2 . Value )
if ! ok {
ctx . errNode ( n . PostfixExpression , "unknown or ambiguous field %q of type %s (%s)" , n . Token2 . Value , st , st0 )
break
}
n . Field = f
ft := f . Type ( )
if f . IsBitField ( ) {
ft = & bitFieldType { Type : ft , field : f . ( * field ) }
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ft } }
break
}
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ft , offset : op . Offset ( ) + f . Offset ( ) } }
case PostfixExpressionPSelect : // PostfixExpression "->" IDENTIFIER
op := n . PostfixExpression . check ( ctx , false , isAsmArg )
n . IsSideEffectsFree = n . PostfixExpression . IsSideEffectsFree
if d := op . Declarator ( ) ; d != nil {
d . Read += ctx . readDelta
}
t := op . Type ( )
if k := t . Decay ( ) . Kind ( ) ; k == Invalid || k != Ptr {
//TODO report error
break
}
st := t . Elem ( )
if k := st . Kind ( ) ; k == Invalid || k != Struct && k != Union {
//TODO report error
break
}
f , ok := st . FieldByName ( n . Token2 . Value )
if ! ok {
//TODO report error
break
}
n . Field = f
ft := f . Type ( )
if f . IsBitField ( ) {
ft = & bitFieldType { Type : ft , field : f . ( * field ) }
}
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ft } }
case PostfixExpressionInc : // PostfixExpression "++"
op := n . PostfixExpression . check ( ctx , false , isAsmArg )
if d := op . Declarator ( ) ; d != nil {
d . SubjectOfIncDec = true
d . Read += ctx . readDelta
d . Write ++
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
case PostfixExpressionDec : // PostfixExpression "--"
op := n . PostfixExpression . check ( ctx , false , isAsmArg )
if d := op . Declarator ( ) ; d != nil {
d . SubjectOfIncDec = true
d . Read += ctx . readDelta
d . Write ++
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) }
case PostfixExpressionComplit : // '(' TypeName ')' '{' InitializerList ',' '}'
//TODO IsSideEffectsFree
if f := ctx . checkFn ; f != nil {
f . CompositeLiterals = append ( f . CompositeLiterals , n )
}
t := n . TypeName . check ( ctx , false , false , nil )
var v * InitializerValue
if n . InitializerList != nil {
n . InitializerList . check ( ctx , & n . InitializerList . list , t , Automatic , 0 , nil , false )
n . InitializerList . setConstZero ( )
v = & InitializerValue { typ : t , initializer : n . InitializerList }
}
n . Operand = & lvalue { Operand : ( & operand { abi : & ctx . cfg . ABI , typ : t , value : v } ) . normalize ( ctx , n ) }
case PostfixExpressionTypeCmp : // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
n . IsSideEffectsFree = true
t1 := n . TypeName . check ( ctx , false , false , nil )
t2 := n . TypeName2 . check ( ctx , false , false , nil )
v := 0
switch {
case t1 . IsArithmeticType ( ) && t2 . IsArithmeticType ( ) :
if t1 . Kind ( ) == t2 . Kind ( ) {
v = 1
}
default :
ctx . errNode ( n , "ICE: __builtin_types_compatible_p(%v, %v)" , t1 , t2 )
}
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : Int64Value ( v ) }
case PostfixExpressionChooseExpr : // "__builtin_choose_expr" '(' ConstantExpression ',' AssignmentExpression ',' AssignmentExpression ')'
n . Operand = noOperand
expr1 := n . AssignmentExpression . check ( ctx , isAsmArg )
if expr1 == nil {
ctx . errNode ( n , "first argument of __builtin_choose_expr must be a constant expression" )
break
}
if ! expr1 . IsConst ( ) {
ctx . errNode ( n , "first argument of __builtin_choose_expr must be a constant expression: %v %v" , expr1 . Value ( ) , expr1 . Type ( ) )
break
}
switch {
case expr1 . IsNonZero ( ) :
n . Operand = n . AssignmentExpression2 . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AssignmentExpression2 . IsSideEffectsFree
default :
n . Operand = n . AssignmentExpression3 . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AssignmentExpression3 . IsSideEffectsFree
}
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * PostfixExpression ) index ( ctx * context , pe , e Operand ) Operand {
var x uintptr
hasx := false
switch v := e . Value ( ) . ( type ) {
case Int64Value :
x = uintptr ( v )
hasx = true
case Uint64Value :
x = uintptr ( v )
hasx = true
}
off := x * pe . Type ( ) . Elem ( ) . Size ( )
switch v := pe . Value ( ) . ( type ) {
case StringValue :
if hasx {
s := StringID ( v ) . String ( )
var v byte
switch {
case x > uintptr ( len ( s ) ) :
//TODO report err
return noOperand
case x < uintptr ( len ( s ) ) :
v = s [ x ]
}
return ( & operand { abi : & ctx . cfg . ABI , typ : pe . Type ( ) . Elem ( ) , value : Int64Value ( v ) } ) . normalize ( ctx , n )
}
case WideStringValue :
if hasx {
s := [ ] rune ( StringID ( v ) . String ( ) )
var v rune
switch {
case x > uintptr ( len ( s ) ) :
//TODO report err
return noOperand
case x < uintptr ( len ( s ) ) :
v = s [ x ]
}
return ( & operand { abi : & ctx . cfg . ABI , typ : pe . Type ( ) . Elem ( ) , value : Int64Value ( v ) } ) . normalize ( ctx , n )
}
}
if d := pe . Declarator ( ) ; d != nil && hasx {
return & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : pe . Type ( ) . Elem ( ) , offset : pe . Offset ( ) + off } , declarator : d }
}
return & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : pe . Type ( ) . Elem ( ) } }
}
func ( n * PostfixExpression ) checkCall ( ctx * context , nd Node , f Type , args [ ] Operand , argList * ArgumentExpressionList ) ( r Operand ) {
r = noOperand
switch f . Kind ( ) {
case Invalid :
return noOperand
case Function :
// ok
case Ptr :
if e := f . Elem ( ) ; e . Kind ( ) == Function {
f = e
break
}
ctx . errNode ( nd , "expected function pointer type: %v, %v" , f , f . Kind ( ) )
return r
default :
ctx . errNode ( nd , "expected function type: %v, %v" , f , f . Kind ( ) )
return r
}
r = & operand { abi : & ctx . cfg . ABI , typ : f . Result ( ) }
params := f . Parameters ( )
if len ( params ) == 1 && params [ 0 ] . Type ( ) . Kind ( ) == Void {
params = nil
if len ( args ) != 0 {
//TODO report error
return r
}
}
for i , arg := range args {
var t Type
switch {
case i < len ( params ) :
//TODO check assignability
t = params [ i ] . Type ( ) . Decay ( )
default :
t = defaultArgumentPromotion ( ctx , nd , arg ) . Type ( )
}
argList . AssignmentExpression . promote = t
argList = argList . ArgumentExpressionList
}
return r
}
func defaultArgumentPromotion ( ctx * context , n Node , op Operand ) Operand {
t := op . Type ( ) . Decay ( )
if arithmeticTypes [ t . Kind ( ) ] {
if t . IsIntegerType ( ) {
return op . integerPromotion ( ctx , n )
}
switch t . Kind ( ) {
case Float :
return op . convertTo ( ctx , n , ctx . cfg . ABI . Type ( Double ) )
}
}
return op
}
func ( n * ArgumentExpressionList ) check ( ctx * context , f * Declarator , isAsmArg bool ) ( r [ ] Operand ) {
for ; n != nil ; n = n . ArgumentExpressionList {
op := n . AssignmentExpression . check ( ctx , isAsmArg )
if op . Type ( ) == nil {
ctx . errNode ( n , "operand has usupported, invalid or incomplete type" )
op = noOperand
} else if op . Type ( ) . IsComplexType ( ) {
ctx . checkFn . CallSiteComplexExpr = append ( ctx . checkFn . CallSiteComplexExpr , n . AssignmentExpression )
}
r = append ( r , op )
if ! ctx . cfg . TrackAssignments {
continue
}
Inspect ( n . AssignmentExpression , func ( n Node , enter bool ) bool {
if ! enter {
return true
}
if x , ok := n . ( * PrimaryExpression ) ; ok {
x . Declarator ( ) . setLHS ( f )
}
return true
} )
}
return r
}
func ( n * Expression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ExpressionAssign : // AssignmentExpression
n . Operand = n . AssignmentExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AssignmentExpression . IsSideEffectsFree
case ExpressionComma : // Expression ',' AssignmentExpression
op := n . Expression . check ( ctx , isAsmArg )
n . Operand = n . AssignmentExpression . check ( ctx , isAsmArg )
if ! op . IsConst ( ) && n . Operand . IsConst ( ) {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : n . Operand . Type ( ) }
}
n . IsSideEffectsFree = n . Expression . IsSideEffectsFree && n . AssignmentExpression . IsSideEffectsFree
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * PrimaryExpression ) check ( ctx * context , implicitFunc , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case PrimaryExpressionIdent : // IDENTIFIER
n . IsSideEffectsFree = true
return n . checkIdentifier ( ctx , implicitFunc )
case PrimaryExpressionInt : // INTCONST
n . IsSideEffectsFree = true
n . Operand = n . intConst ( ctx )
case PrimaryExpressionFloat : // FLOATCONST
n . IsSideEffectsFree = true
if ctx . mode & mIntConstExpr != 0 && ctx . mode & mIntConstExprFloat == 0 {
ctx . errNode ( n , "invalid integer constant expression" )
break
}
n . Operand = n . floatConst ( ctx )
case PrimaryExpressionEnum : // ENUMCONST
n . IsSideEffectsFree = true
if e := n . resolvedIn . enumerator ( n . Token . Value , n . Token ) ; e != nil {
op := e . Operand . ( * operand )
op . typ = ctx . cfg . ABI . Type ( Int ) // [0] 6.4.4.3/2
n . Operand = op
break
}
//TODO report err
case PrimaryExpressionChar : // CHARCONST
n . IsSideEffectsFree = true
s := [ ] rune ( n . Token . Value . String ( ) )
var v Value
switch {
case s [ 0 ] <= 255 :
// If an integer character constant contains a single character or escape
// sequence, its value is the one that results when an object with type char
// whose value is that of the single character or escape sequence is converted
// to type int.
switch {
case ctx . cfg . ABI . SignedChar :
v = Int64Value ( int8 ( s [ 0 ] ) )
default :
v = Int64Value ( s [ 0 ] )
}
default :
v = Int64Value ( s [ 0 ] )
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : v } ) . normalize ( ctx , n )
case PrimaryExpressionLChar : // LONGCHARCONST
n . IsSideEffectsFree = true
s := [ ] rune ( n . Token . Value . String ( ) )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : wcharT ( ctx , n . lexicalScope , n . Token ) , value : Int64Value ( s [ 0 ] ) } ) . normalize ( ctx , n )
case PrimaryExpressionString : // STRINGLITERAL
n . IsSideEffectsFree = true
ctx . not ( n , mIntConstExpr )
typ := ctx . cfg . ABI . Type ( Char )
b := typ . base ( )
b . align = byte ( typ . Align ( ) )
b . fieldAlign = byte ( typ . FieldAlign ( ) )
b . kind = byte ( Array )
sz := uintptr ( len ( n . Token . Value . String ( ) ) ) + 1 //TODO set sz in cpp
arr := & arrayType { typeBase : b , decay : ctx . cfg . ABI . Ptr ( n , typ ) , elem : typ , length : sz }
arr . setLen ( sz )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : arr , value : StringValue ( n . Token . Value ) } ) . normalize ( ctx , n )
case PrimaryExpressionLString : // LONGSTRINGLITERAL
n . IsSideEffectsFree = true
ctx . not ( n , mIntConstExpr )
typ := wcharT ( ctx , n . lexicalScope , n . Token )
b := typ . base ( )
b . align = byte ( typ . Align ( ) )
b . fieldAlign = byte ( typ . FieldAlign ( ) )
b . kind = byte ( Array )
sz := uintptr ( len ( [ ] rune ( n . Token . Value . String ( ) ) ) ) + 1 //TODO set sz in cpp
arr := & arrayType { typeBase : b , decay : ctx . cfg . ABI . Ptr ( n , typ ) , elem : typ , length : sz }
arr . setLen ( sz )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : arr , value : WideStringValue ( n . Token . Value ) } ) . normalize ( ctx , n )
case PrimaryExpressionExpr : // '(' Expression ')'
n . Operand = n . Expression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . Expression . IsSideEffectsFree
case PrimaryExpressionStmt : // '(' CompoundStatement ')'
//TODO IsSideEffectsFree
ctx . not ( n , mIntConstExpr )
n . Operand = n . CompoundStatement . check ( ctx )
if n . Operand == noOperand {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Void ) }
}
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func wcharT ( ctx * context , s Scope , tok Token ) Type {
if t := ctx . wcharT ; t != nil {
return t
}
t := ctx . stddef ( idWCharT , s , tok )
if t . Kind ( ) != Invalid {
ctx . wcharT = t
}
return t
}
func ( n * PrimaryExpression ) checkIdentifier ( ctx * context , implicitFunc bool ) Operand {
ctx . not ( n , mIntConstExpr )
var d * Declarator
nm := n . Token . Value
if n . resolvedIn == nil {
if ctx . cfg . RejectLateBinding && ! ctx . cfg . ignoreUndefinedIdentifiers {
ctx . errNode ( n , "front-end: undefined: %s" , n . Token . Value )
return noOperand
}
out :
for s := n . lexicalScope ; s != nil ; s = s . Parent ( ) {
for _ , v := range s [ nm ] {
switch x := v . ( type ) {
case * Enumerator :
break out
case * Declarator :
if x . IsTypedefName {
d = nil
break out
}
n . resolvedIn = s
n . resolvedTo = x
d = x
t := d . Type ( )
if t != nil && t . Kind ( ) == Function {
if d . fnDef {
break out
}
continue
}
if t != nil && ! t . IsIncomplete ( ) {
break out
}
case * EnumSpecifier , * StructOrUnionSpecifier , * StructDeclarator , * LabeledStatement :
// nop
default :
panic ( todo ( "" ) )
}
}
}
}
if d == nil && n . resolvedIn != nil {
d = n . resolvedIn . declarator ( n . Token . Value , n . Token )
}
if d == nil && ! ctx . cfg . DisableBuiltinResolution {
d = builtin ( ctx , nm )
}
if d == nil {
_ , ok := gccKeywords [ nm ]
if ! ok && implicitFunc {
d := & Declarator {
DirectDeclarator : & DirectDeclarator {
lexicalScope : ctx . ast . Scope ,
Case : DirectDeclaratorFuncIdent ,
DirectDeclarator : & DirectDeclarator {
lexicalScope : ctx . ast . Scope ,
Case : DirectDeclaratorIdent ,
Token : Token { Value : nm } ,
} ,
} ,
implicit : true ,
}
ed := & ExternalDeclaration {
Case : ExternalDeclarationDecl ,
Declaration : & Declaration {
DeclarationSpecifiers : & DeclarationSpecifiers {
Case : DeclarationSpecifiersTypeSpec ,
TypeSpecifier : & TypeSpecifier {
Case : TypeSpecifierInt ,
} ,
} ,
InitDeclaratorList : & InitDeclaratorList {
InitDeclarator : & InitDeclarator {
Case : InitDeclaratorDecl ,
Declarator : d ,
} ,
} ,
} ,
}
ed . check ( ctx )
n . Operand = & funcDesignator { Operand : & operand { abi : & ctx . cfg . ABI , typ : d . Type ( ) } , declarator : d }
return n . Operand
}
if ! ctx . cfg . ignoreUndefinedIdentifiers {
ctx . errNode ( n , "front-end: undefined: %s" , n . Token . Value )
}
return noOperand
}
if d == nil {
if ! ctx . cfg . ignoreUndefinedIdentifiers {
ctx . errNode ( n , "front-end: undefined: %s" , n . Token . Value )
}
return noOperand
}
switch d . Linkage {
case Internal :
if d . IsStatic ( ) {
break
}
fallthrough
case External :
s := n . resolvedIn
if s . Parent ( ) == nil {
break
}
for s . Parent ( ) != nil {
s = s . Parent ( )
}
if d2 := s . declarator ( n . Token . Value , Token { } ) ; d2 != nil {
d = d2
}
}
if d . Type ( ) == nil {
ctx . errNode ( d , "unresolved type of: %s" , n . Token . Value )
return noOperand
}
d . Read += ctx . readDelta
switch t := d . Type ( ) ; t . Kind ( ) {
case Function :
n . Operand = & funcDesignator { Operand : & operand { abi : & ctx . cfg . ABI , typ : t } , declarator : d }
default :
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : t } , declarator : d }
}
if ! ctx . capture {
return n . Operand
}
for s := n . lexicalScope ; s != nil ; s = s . Parent ( ) {
if _ , ok := s [ nm ] ; ok {
return n . Operand // d in fn scope
}
if _ , ok := s [ idClosure ] ; ok { // d in outer scope
if ctx . closure == nil {
ctx . closure = map [ StringID ] struct { } { } //TODO capture the PrimaryExpression, not the declarator name
}
ctx . closure [ nm ] = struct { } { }
return n . Operand
}
}
panic ( todo ( "" ) )
}
func builtin ( ctx * context , nm StringID ) * Declarator {
id := dict . sid ( "__builtin_" + nm . String ( ) )
a := ctx . ast . Scope [ id ]
if len ( a ) == 0 {
return nil
}
switch x := a [ 0 ] . ( type ) {
case * Declarator :
if x . fnDef || x . IsFunctionPrototype ( ) {
return x
}
}
return nil
}
func ( n * PrimaryExpression ) floatConst ( ctx * context ) Operand {
s0 := n . Token . String ( )
s := s0
var cplx , suff string
loop2 :
for i := len ( s ) - 1 ; i > 0 ; i -- {
switch s0 [ i ] {
case 'l' , 'L' :
s = s [ : i ]
if ctx . cfg . LongDoubleIsDouble {
break
}
suff += "l"
case 'f' , 'F' :
s = s [ : i ]
suff += "f"
case 'i' , 'I' , 'j' , 'J' :
s = s [ : i ]
cplx += "i"
default :
break loop2
}
}
if len ( suff ) > 1 || len ( cplx ) > 1 {
ctx . errNode ( n , "invalid number format" )
return noOperand
}
var v float64
var err error
prec := uint ( 64 )
if suff == "l" {
prec = longDoublePrec
}
var bf * big . Float
switch {
case suff == "l" || strings . Contains ( s , "p" ) || strings . Contains ( s , "P" ) :
bf , _ , err = big . ParseFloat ( strings . ToLower ( s ) , 0 , prec , big . ToNearestEven )
if err == nil {
v , _ = bf . Float64 ( )
}
default :
v , err = strconv . ParseFloat ( s , 64 )
}
if err != nil {
switch {
case ! strings . HasPrefix ( s , "-" ) && strings . Contains ( err . Error ( ) , "value out of range" ) :
// linux_386/usr/include/math.h
//
// /* Value returned on overflow. With IEEE 754 floating point, this is
// +Infinity, otherwise the largest representable positive value. */
// #if __GNUC_PREREQ (3, 3)
// # define HUGE_VAL (__builtin_huge_val ())
// #else
// /* This may provoke compiler warnings, and may not be rounded to
// +Infinity in all IEEE 754 rounding modes, but is the best that can
// be done in ISO C while remaining a constant expression. 10,000 is
// greater than the maximum (decimal) exponent for all supported
// floating-point formats and widths. */
// # define HUGE_VAL 1e10000
// #endif
v = math . Inf ( 1 )
default :
ctx . errNode ( n , "%v" , err )
return noOperand
}
}
// [0]6.4.4.2
switch suff {
case "" :
switch {
case cplx != "" :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ComplexDouble ) , value : Complex128Value ( complex ( 0 , v ) ) } ) . normalize ( ctx , n )
default :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Double ) , value : Float64Value ( v ) } ) . normalize ( ctx , n )
}
case "f" :
switch {
case cplx != "" :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ComplexFloat ) , value : Complex64Value ( complex ( 0 , float32 ( v ) ) ) } ) . normalize ( ctx , n )
default :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Float ) , value : Float32Value ( float32 ( v ) ) } ) . normalize ( ctx , n )
}
case "l" :
switch {
case cplx != "" :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( ComplexLongDouble ) , value : Complex256Value { & Float128Value { N : big . NewFloat ( 0 ) } , & Float128Value { N : bf } } } ) . normalize ( ctx , n )
default :
return ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( LongDouble ) , value : & Float128Value { N : bf } } ) . normalize ( ctx , n )
}
default :
//dbg("%q %q %q %q %v", s0, s, suff, cplx, err)
panic ( "TODO" )
}
}
func ( n * PrimaryExpression ) intConst ( ctx * context ) Operand {
var val uint64
s0 := n . Token . String ( )
s := strings . TrimRight ( s0 , "uUlL" )
var decadic bool
switch {
case strings . HasPrefix ( s , "0x" ) || strings . HasPrefix ( s , "0X" ) :
var err error
if val , err = strconv . ParseUint ( s [ 2 : ] , 16 , 64 ) ; err != nil {
ctx . errNode ( n , "%v" , err )
return nil
}
case strings . HasPrefix ( s , "0b" ) || strings . HasPrefix ( s , "0B" ) :
var err error
if val , err = strconv . ParseUint ( s [ 2 : ] , 2 , 64 ) ; err != nil {
ctx . errNode ( n , "%v" , err )
return nil
}
case strings . HasPrefix ( s , "0" ) :
var err error
if val , err = strconv . ParseUint ( s , 8 , 64 ) ; err != nil {
ctx . errNode ( n , "%v" , err )
return nil
}
default :
decadic = true
var err error
if val , err = strconv . ParseUint ( s , 10 , 64 ) ; err != nil {
ctx . errNode ( n , "%v" , err )
return nil
}
}
suffix := s0 [ len ( s ) : ]
switch suffix = strings . ToLower ( suffix ) ; suffix {
case "" :
if decadic {
return intConst ( ctx , n , s0 , val , Int , Long , LongLong )
}
return intConst ( ctx , n , s0 , val , Int , UInt , Long , ULong , LongLong , ULongLong )
case "u" :
return intConst ( ctx , n , s0 , val , UInt , ULong , ULongLong )
case "l" :
if decadic {
return intConst ( ctx , n , s0 , val , Long , LongLong )
}
return intConst ( ctx , n , s0 , val , Long , ULong , LongLong , ULongLong )
case "lu" , "ul" :
return intConst ( ctx , n , s0 , val , ULong , ULongLong )
case "ll" :
if decadic {
return intConst ( ctx , n , s0 , val , LongLong )
}
return intConst ( ctx , n , s0 , val , LongLong , ULongLong )
case "llu" , "ull" :
return intConst ( ctx , n , s0 , val , ULongLong )
default :
ctx . errNode ( n , "invalid suffix: %v" , s0 )
return nil
}
}
func intConst ( ctx * context , n Node , s string , val uint64 , list ... Kind ) Operand {
abi := ctx . cfg . ABI
b := bits . Len64 ( val )
for _ , k := range list {
sign := 0
if abi . isSignedInteger ( k ) {
sign = 1
}
if abi . size ( k ) * 8 >= b + sign {
switch {
case sign == 0 :
return ( & operand { abi : & ctx . cfg . ABI , typ : abi . Type ( k ) , value : Uint64Value ( val ) } ) . normalize ( ctx , n )
default :
return ( & operand { abi : & ctx . cfg . ABI , typ : abi . Type ( k ) , value : Int64Value ( val ) } ) . normalize ( ctx , n )
}
}
}
ctx . errNode ( n , "invalid integer constant %v" , s )
return nil
}
func ( n * ConditionalExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ConditionalExpressionLOr : // LogicalOrExpression
n . Operand = n . LogicalOrExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree
case ConditionalExpressionCond : // LogicalOrExpression '?' Expression ':' ConditionalExpression
op := n . LogicalOrExpression . check ( ctx , isAsmArg )
// The first operand shall have scalar type.
if ! op . Type ( ) . Decay ( ) . IsScalarType ( ) {
//TODO report error
break
}
a := n . Expression . check ( ctx , isAsmArg )
b := n . ConditionalExpression . check ( ctx , isAsmArg )
at := a . Type ( ) . Decay ( )
bt := b . Type ( ) . Decay ( )
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree && ( n . Expression == nil || n . Expression . IsSideEffectsFree ) && n . ConditionalExpression . IsSideEffectsFree
var val Value
if op . Value ( ) != nil {
switch {
case op . IsZero ( ) :
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree && n . ConditionalExpression . IsSideEffectsFree
default :
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree && n . Expression . IsSideEffectsFree
}
if a . Value ( ) != nil && b . Value ( ) != nil { //TODO not needed both non nil
switch {
case op . IsZero ( ) :
val = b . Value ( )
default :
val = a . Value ( )
}
}
}
if a . Type ( ) . Kind ( ) == Invalid && b . Type ( ) . Kind ( ) == Invalid {
return noOperand
}
// One of the following shall hold for the second and third
// operands:
//TODO — both operands have the same structure or union type;
//TODO — one operand is a pointer to an object or incomplete type and the other is a pointer to a
//TODO qualified or unqualified version of void.
switch {
// — both operands have arithmetic type;
case a . Type ( ) . IsArithmeticType ( ) && b . Type ( ) . IsArithmeticType ( ) :
// If both the second and third operands have
// arithmetic type, the result type that would be
// determined by the usual arithmetic conversions, were
// they applied to those two operands,
// is the type of the result.
op , _ := usualArithmeticConversions ( ctx , n , a , b , true )
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : op . Type ( ) , value : val } ) . normalize ( ctx , n )
// — both operands have void type;
case a . Type ( ) . Kind ( ) == Void && b . Type ( ) . Kind ( ) == Void :
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : val } ) . normalize ( ctx , n )
// — one operand is a pointer and the other is a null pointer constant;
case ( a . Type ( ) . Kind ( ) == Ptr || a . Type ( ) . Kind ( ) == Function ) && b . IsZero ( ) :
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : val } ) . normalize ( ctx , n )
case ( b . Type ( ) . Kind ( ) == Ptr || b . Type ( ) . Kind ( ) == Function ) && a . IsZero ( ) :
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : b . Type ( ) , value : val } ) . normalize ( ctx , n )
// — both operands are pointers to qualified or unqualified versions of compatible types;
case at . Kind ( ) == Ptr && bt . Kind ( ) == Ptr :
//TODO check compatible
//TODO if !at.isCompatibleIgnoreQualifiers(bt) {
//TODO trc("%v: XXXX %v ? %v", n.Token2.Position(), at, bt)
//TODO ctx.assignmentCompatibilityErrorCond(&n.Token2, at, bt)
//TODO }
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : n . Expression . Operand . Type ( ) , value : val } ) . normalize ( ctx , n )
case a . Type ( ) . Kind ( ) == Ptr && a . Type ( ) . Elem ( ) . Kind ( ) == Function && b . Type ( ) . Kind ( ) == Function :
//TODO check compatible
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : val } ) . normalize ( ctx , n )
case b . Type ( ) . Kind ( ) == Ptr && b . Type ( ) . Elem ( ) . Kind ( ) == Function && a . Type ( ) . Kind ( ) == Function :
//TODO check compatible
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : b . Type ( ) , value : val } ) . normalize ( ctx , n )
case a . Type ( ) . Kind ( ) != Invalid :
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : val } ) . normalize ( ctx , n )
case b . Type ( ) . Kind ( ) != Invalid :
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : b . Type ( ) , value : val } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * LogicalOrExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case LogicalOrExpressionLAnd : // LogicalAndExpression
n . Operand = n . LogicalAndExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . LogicalAndExpression . IsSideEffectsFree
case LogicalOrExpressionLOr : // LogicalOrExpression "||" LogicalAndExpression
lop := n . LogicalOrExpression . check ( ctx , isAsmArg )
rop := n . LogicalAndExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . LogicalOrExpression . IsSideEffectsFree && n . LogicalAndExpression . IsSideEffectsFree ||
lop . Value ( ) != nil && lop . IsNonZero ( ) && n . LogicalOrExpression . IsSideEffectsFree
var v Value
if lop . Value ( ) != nil && rop . Value ( ) != nil { //TODO lop.IsNonZero shortcut
switch {
case n . LogicalOrExpression . Operand . IsNonZero ( ) || n . LogicalAndExpression . Operand . IsNonZero ( ) :
v = Int64Value ( 1 )
default :
v = Int64Value ( 0 )
}
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : v } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * LogicalAndExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case LogicalAndExpressionOr : // InclusiveOrExpression
n . Operand = n . InclusiveOrExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . InclusiveOrExpression . IsSideEffectsFree
case LogicalAndExpressionLAnd : // LogicalAndExpression "&&" InclusiveOrExpression
lop := n . LogicalAndExpression . check ( ctx , isAsmArg )
rop := n . InclusiveOrExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . LogicalAndExpression . IsSideEffectsFree && n . InclusiveOrExpression . IsSideEffectsFree ||
lop . Value ( ) != nil && lop . IsZero ( ) && n . LogicalAndExpression . IsSideEffectsFree
var v Value
if lop . Value ( ) != nil && rop . Value ( ) != nil { //TODO lop.IsZero shortcut
switch {
case n . LogicalAndExpression . Operand . IsNonZero ( ) && n . InclusiveOrExpression . Operand . IsNonZero ( ) :
v = Int64Value ( 1 )
default :
v = Int64Value ( 0 )
}
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) , value : v } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * InclusiveOrExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case InclusiveOrExpressionXor : // ExclusiveOrExpression
n . Operand = n . ExclusiveOrExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ExclusiveOrExpression . IsSideEffectsFree
case InclusiveOrExpressionOr : // InclusiveOrExpression '|' ExclusiveOrExpression
a := n . InclusiveOrExpression . check ( ctx , isAsmArg )
b := n . ExclusiveOrExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . InclusiveOrExpression . IsSideEffectsFree && n . ExclusiveOrExpression . IsSideEffectsFree
n . promote = noType
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorIntegerArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operands must be integers" )
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . or ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func checkBinaryVectorIntegerArtithmetic ( ctx * context , n Node , a , b Operand ) Operand {
var rt Type
if a . Type ( ) . Kind ( ) == Vector {
rt = a . Type ( )
a = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) . Elem ( ) }
}
if b . Type ( ) . Kind ( ) == Vector {
if rt == nil {
rt = b . Type ( )
}
b = & operand { abi : & ctx . cfg . ABI , typ : b . Type ( ) . Elem ( ) }
}
a , b = usualArithmeticConversions ( ctx , n , a , b , true )
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operands must be integers" )
}
return & operand { abi : & ctx . cfg . ABI , typ : rt }
}
func ( n * ExclusiveOrExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ExclusiveOrExpressionAnd : // AndExpression
n . Operand = n . AndExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AndExpression . IsSideEffectsFree
case ExclusiveOrExpressionXor : // ExclusiveOrExpression '^' AndExpression
a := n . ExclusiveOrExpression . check ( ctx , isAsmArg )
b := n . AndExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ExclusiveOrExpression . IsSideEffectsFree && n . AndExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorIntegerArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operands must be integers" )
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . xor ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * AndExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case AndExpressionEq : // EqualityExpression
n . Operand = n . EqualityExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . EqualityExpression . IsSideEffectsFree
case AndExpressionAnd : // AndExpression '&' EqualityExpression
a := n . AndExpression . check ( ctx , isAsmArg )
b := n . EqualityExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AndExpression . IsSideEffectsFree && n . EqualityExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorIntegerArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( n , "operands must be integers" )
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . and ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * EqualityExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
switch n . Case {
case EqualityExpressionRel : // RelationalExpression
n . Operand = n . RelationalExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . RelationalExpression . IsSideEffectsFree
case
EqualityExpressionEq , // EqualityExpression "==" RelationalExpression
EqualityExpressionNeq : // EqualityExpression "!=" RelationalExpression
op := & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) }
n . Operand = op
lo := n . EqualityExpression . check ( ctx , isAsmArg )
ro := n . RelationalExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . EqualityExpression . IsSideEffectsFree && n . RelationalExpression . IsSideEffectsFree
lt := lo . Type ( ) . Decay ( )
rt := ro . Type ( ) . Decay ( )
n . promote = noType
ok := false
switch {
case lo . Type ( ) . Kind ( ) == Vector && ro . Type ( ) . Kind ( ) == Vector :
n . Operand = checkVectorComparison ( ctx , n , lo . Type ( ) , ro . Type ( ) )
return n . Operand
case lt . IsArithmeticType ( ) && rt . IsArithmeticType ( ) :
op , _ := usualArithmeticConversions ( ctx , n , lo , ro , true )
n . promote = op . Type ( )
ok = true
case lt . Kind ( ) == Ptr && ( rt . Kind ( ) == Ptr || rt . IsIntegerType ( ) ) :
n . promote = lt
//TODO
case ( lt . Kind ( ) == Ptr || lt . IsIntegerType ( ) ) && rt . Kind ( ) == Ptr :
n . promote = rt
//TODO
case lt . Kind ( ) == Function :
n . promote = ctx . cfg . ABI . Ptr ( n , lt )
case rt . Kind ( ) == Function :
n . promote = ctx . cfg . ABI . Ptr ( n , rt )
default :
//TODO report error
}
if n . promote . Kind ( ) == Invalid || ! ok {
break
}
lo = lo . convertTo ( ctx , n , n . promote )
ro = ro . convertTo ( ctx , n , n . promote )
if a , b := lo . Value ( ) , ro . Value ( ) ; a != nil && b != nil {
switch n . Case {
case EqualityExpressionEq : // EqualityExpression "==" RelationalExpression
op . value = a . eq ( b )
case EqualityExpressionNeq : // EqualityExpression "!=" RelationalExpression
op . value = a . neq ( b )
}
}
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func checkVectorComparison ( ctx * context , n Node , a , b Type ) ( r Operand ) {
a = a . underlyingType ( )
b = b . underlyingType ( )
rt := * a . ( * vectorType )
rt . elem = ctx . cfg . ABI . Type ( Int )
r = & operand { abi : & ctx . cfg . ABI , typ : & rt }
x := a . Elem ( )
y := b . Elem ( )
if x . Kind ( ) != y . Kind ( ) {
ctx . errNode ( n , "cannot compare vectors of different element types: %s and %s" , x , y )
}
return r
}
func ( n * RelationalExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case RelationalExpressionShift : // ShiftExpression
n . Operand = n . ShiftExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ShiftExpression . IsSideEffectsFree
case
RelationalExpressionLt , // RelationalExpression '<' ShiftExpression
RelationalExpressionGt , // RelationalExpression '>' ShiftExpression
RelationalExpressionLeq , // RelationalExpression "<=" ShiftExpression
RelationalExpressionGeq : // RelationalExpression ">=" ShiftExpression
n . promote = noType
op := & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Type ( Int ) }
n . Operand = op
lo := n . RelationalExpression . check ( ctx , isAsmArg )
ro := n . ShiftExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . RelationalExpression . IsSideEffectsFree && n . ShiftExpression . IsSideEffectsFree
if lo . Type ( ) . Kind ( ) == Vector && ro . Type ( ) . Kind ( ) == Vector {
n . Operand = checkVectorComparison ( ctx , n , lo . Type ( ) , ro . Type ( ) )
break
}
if lo . Type ( ) . IsComplexType ( ) || ro . Type ( ) . IsComplexType ( ) {
ctx . errNode ( & n . Token , "complex numbers are not ordered" )
break
}
lt := lo . Type ( ) . Decay ( )
rt := ro . Type ( ) . Decay ( )
n . promote = noType
ok := true
switch {
case lt . IsRealType ( ) && rt . IsRealType ( ) :
op , _ := usualArithmeticConversions ( ctx , n , lo , ro , true )
n . promote = op . Type ( )
case lt . Kind ( ) == Ptr && ( rt . Kind ( ) == Ptr || rt . IsIntegerType ( ) ) :
n . promote = lt
//TODO
case ( lt . Kind ( ) == Ptr || lt . IsIntegerType ( ) ) && rt . Kind ( ) == Ptr :
n . promote = rt
//TODO
default :
//TODO report error
ok = false
}
if n . promote . Kind ( ) == Invalid || ! ok {
break
}
lo = lo . convertTo ( ctx , n , n . promote )
ro = ro . convertTo ( ctx , n , n . promote )
if a , b := lo . Value ( ) , ro . Value ( ) ; a != nil && b != nil {
switch n . Case {
case RelationalExpressionLt : // RelationalExpression '<' ShiftExpression
op . value = a . lt ( b )
case RelationalExpressionGt : // RelationalExpression '>' ShiftExpression
op . value = a . gt ( b )
case RelationalExpressionLeq : // RelationalExpression "<=" ShiftExpression
op . value = a . le ( b )
case RelationalExpressionGeq : // RelationalExpression ">=" ShiftExpression
op . value = a . ge ( b )
}
}
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * ShiftExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case ShiftExpressionAdd : // AdditiveExpression
n . Operand = n . AdditiveExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AdditiveExpression . IsSideEffectsFree
case ShiftExpressionLsh : // ShiftExpression "<<" AdditiveExpression
a := n . ShiftExpression . check ( ctx , isAsmArg )
b := n . AdditiveExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ShiftExpression . IsSideEffectsFree && n . AdditiveExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorIntegerArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
//TODO report err
break
}
a = a . integerPromotion ( ctx , n )
b = b . integerPromotion ( ctx , n )
n . promote = b . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . lsh ( b . Value ( ) ) } ) . normalize ( ctx , n )
case ShiftExpressionRsh : // ShiftExpression ">>" AdditiveExpression
a := n . ShiftExpression . check ( ctx , isAsmArg )
b := n . AdditiveExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . ShiftExpression . IsSideEffectsFree && n . AdditiveExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorIntegerArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
//TODO report err
break
}
a = a . integerPromotion ( ctx , n )
b = b . integerPromotion ( ctx , n )
n . promote = b . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . rsh ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * AdditiveExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case AdditiveExpressionMul : // MultiplicativeExpression
n . Operand = n . MultiplicativeExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . MultiplicativeExpression . IsSideEffectsFree
case AdditiveExpressionAdd : // AdditiveExpression '+' MultiplicativeExpression
n . promote = noType
a := n . AdditiveExpression . check ( ctx , isAsmArg )
b := n . MultiplicativeExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AdditiveExpression . IsSideEffectsFree && n . MultiplicativeExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorArtithmetic ( ctx , n , a , b )
break
}
if t := a . Type ( ) . Decay ( ) ; t . Kind ( ) == Ptr && b . Type ( ) . IsScalarType ( ) {
var x uintptr
hasx := false
switch v := b . Value ( ) . ( type ) {
case Int64Value :
x = uintptr ( v )
hasx = true
case Uint64Value :
x = uintptr ( v )
hasx = true
}
off := x * a . Type ( ) . Elem ( ) . Size ( )
switch y := a . Value ( ) . ( type ) {
case StringValue :
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , a . Type ( ) . Elem ( ) ) , value : y , offset : a . Offset ( ) + off }
default :
switch {
case a . Value ( ) == nil && a . Declarator ( ) != nil && hasx :
n . Operand = & lvalue { Operand : & operand { abi : & ctx . cfg . ABI , typ : ctx . cfg . ABI . Ptr ( n , a . Type ( ) . Elem ( ) ) , offset : a . Offset ( ) + off } , declarator : a . Declarator ( ) }
default :
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : t }
}
}
break
}
if t := b . Type ( ) . Decay ( ) ; t . Kind ( ) == Ptr && a . Type ( ) . IsScalarType ( ) {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : t }
break
}
if ! a . Type ( ) . IsArithmeticType ( ) || ! b . Type ( ) . IsArithmeticType ( ) {
//TODO report error
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . add ( b . Value ( ) ) } ) . normalize ( ctx , n )
case AdditiveExpressionSub : // AdditiveExpression '-' MultiplicativeExpression
n . promote = noType
a := n . AdditiveExpression . check ( ctx , isAsmArg )
b := n . MultiplicativeExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . AdditiveExpression . IsSideEffectsFree && n . MultiplicativeExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorArtithmetic ( ctx , n , a , b )
break
}
if a . Type ( ) . Decay ( ) . Kind ( ) == Ptr && b . Type ( ) . Decay ( ) . Kind ( ) == Ptr {
var val Value
if a . Value ( ) != nil && b . Value ( ) != nil {
ae := a . Type ( ) . Decay ( ) . Elem ( )
be := b . Type ( ) . Decay ( ) . Elem ( )
switch {
case ae . Size ( ) == be . Size ( ) :
var d int64
switch x := a . Value ( ) . ( type ) {
case Int64Value :
d = int64 ( x )
case Uint64Value :
d = int64 ( x )
}
switch x := b . Value ( ) . ( type ) {
case Int64Value :
val = Int64Value ( d - int64 ( x ) )
case Uint64Value :
val = Int64Value ( d - int64 ( x ) )
}
default :
ctx . errNode ( n , "difference of pointers of differently sized elements" )
}
}
pt := ptrdiffT ( ctx , n . lexicalScope , n . Token )
n . promote = pt
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : pt , value : val }
if val != nil {
n . Operand = n . Operand . convertTo ( ctx , n , a . Type ( ) )
}
break
}
if t := a . Type ( ) . Decay ( ) ; t . Kind ( ) == Ptr && b . Type ( ) . IsScalarType ( ) {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : t }
break
}
if ! a . Type ( ) . IsArithmeticType ( ) || ! b . Type ( ) . IsArithmeticType ( ) {
//TODO report error
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . sub ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func checkBinaryVectorArtithmetic ( ctx * context , n Node , a , b Operand ) Operand {
var rt Type
if a . Type ( ) . Kind ( ) == Vector {
rt = a . Type ( )
a = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) . Elem ( ) }
}
if b . Type ( ) . Kind ( ) == Vector {
if rt == nil {
rt = b . Type ( )
}
b = & operand { abi : & ctx . cfg . ABI , typ : b . Type ( ) . Elem ( ) }
}
usualArithmeticConversions ( ctx , n , a , b , true )
return & operand { abi : & ctx . cfg . ABI , typ : rt }
}
func ptrdiffT ( ctx * context , s Scope , tok Token ) Type {
if t := ctx . ptrdiffT ; t != nil {
return t
}
t := ctx . stddef ( idPtrdiffT , s , tok )
if t . Kind ( ) != Invalid {
ctx . ptrdiffT = t
}
return t
}
func ( n * MultiplicativeExpression ) check ( ctx * context , isAsmArg bool ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand //TODO-
switch n . Case {
case MultiplicativeExpressionCast : // CastExpression
n . Operand = n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . CastExpression . IsSideEffectsFree
case MultiplicativeExpressionMul : // MultiplicativeExpression '*' CastExpression
a := n . MultiplicativeExpression . check ( ctx , isAsmArg )
b := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . MultiplicativeExpression . IsSideEffectsFree && n . CastExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsArithmeticType ( ) || ! b . Type ( ) . IsArithmeticType ( ) {
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . mul ( b . Value ( ) ) } ) . normalize ( ctx , n )
case MultiplicativeExpressionDiv : // MultiplicativeExpression '/' CastExpression
a := n . MultiplicativeExpression . check ( ctx , isAsmArg )
b := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . MultiplicativeExpression . IsSideEffectsFree && n . CastExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsArithmeticType ( ) || ! b . Type ( ) . IsArithmeticType ( ) {
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . div ( b . Value ( ) ) } ) . normalize ( ctx , n )
case MultiplicativeExpressionMod : // MultiplicativeExpression '%' CastExpression
a := n . MultiplicativeExpression . check ( ctx , isAsmArg )
b := n . CastExpression . check ( ctx , isAsmArg )
n . IsSideEffectsFree = n . MultiplicativeExpression . IsSideEffectsFree && n . CastExpression . IsSideEffectsFree
if a . Type ( ) . Kind ( ) == Vector || b . Type ( ) . Kind ( ) == Vector {
n . Operand = checkBinaryVectorArtithmetic ( ctx , n , a , b )
break
}
if ! a . Type ( ) . IsArithmeticType ( ) || ! b . Type ( ) . IsArithmeticType ( ) {
break
}
if ! a . Type ( ) . IsIntegerType ( ) || ! b . Type ( ) . IsIntegerType ( ) {
ctx . errNode ( & n . Token , "the operands of the %% operator shall have integer type." ) // [0] 6.5.5, 2
break
}
a , b = usualArithmeticConversions ( ctx , & n . Token , a , b , true )
n . promote = a . Type ( )
if a . Value ( ) == nil || b . Value ( ) == nil {
n . Operand = & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) }
break
}
n . Operand = ( & operand { abi : & ctx . cfg . ABI , typ : a . Type ( ) , value : a . Value ( ) . mod ( b . Value ( ) ) } ) . normalize ( ctx , n )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * Declarator ) check ( ctx * context , td typeDescriptor , typ Type , tld bool ) Type {
if n == nil {
n . typ = ctx . cfg . ABI . Type ( Int )
return noType
}
typ = n . Pointer . check ( ctx , typ )
n . td = td
if attr := n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) ) ; len ( attr ) != 0 {
typ = & attributedType { typ , attr }
}
n . typ = n . DirectDeclarator . check ( ctx , typ )
hasStorageSpecifiers := td . typedef ( ) || td . extern ( ) || td . static ( ) ||
td . auto ( ) || td . register ( ) || td . threadLocal ( )
typ = n . typ
if typ == nil {
n . typ = ctx . cfg . ABI . Type ( Int )
ctx . errNode ( n , "declarator has unsupported, invalid or incomplete type" )
return noType
}
if typ . Kind ( ) == Array && typ . IsVLA ( ) {
if f := ctx . checkFn ; f != nil {
f . VLAs = append ( f . VLAs , n )
}
}
// 6.2.2 Linkages of identifiers
n . Linkage = None
switch {
case tld && td . static ( ) :
// 3: If the declaration of a file scope identifier for an object or a function
// contains the storage-class specifier static, the identifier has internal
// linkage.
n . Linkage = Internal
case td . extern ( ) :
//TODO
//
// 4: For an identifier declared with the storage-class specifier extern in a
// scope in which a prior declaration of that identifier is visible, 23) if the
// prior declaration specifies internal or external linkage, the linkage of the
// identifier at the later declaration is the same as the linkage specified at
// the prior declaration. If no prior declaration is visible, or if the prior
// declaration specifies no linkage, then the identifier has external linkage.
n . Linkage = External
case
! n . IsParameter && typ . Kind ( ) == Function && ! hasStorageSpecifiers ,
tld && ! hasStorageSpecifiers :
// 5: If the declaration of an identifier for a function has no storage-class
// specifier, its linkage is determined exactly as if it were declared with the
// storage-class specifier extern.
n . Linkage = External
}
// 6.2.4 Storage durations of objects
switch {
case n . Linkage == External , n . Linkage == Internal , td . static ( ) :
// 2: An object whose identifier is declared with external or internal linkage,
// or with the storage-class specifier static has static storage duration. Its
// lifetime is the entire execution of the program and its stored value is
// initialized only once, prior to
// program startup.
n . StorageClass = Static
case n . Linkage == None && ! td . static ( ) :
// 4: An object whose identifier is declared with no linkage and without the
// storage-class specifier static has automatic storage duration.
n . StorageClass = Automatic
}
switch {
case n . typ . Kind ( ) == Invalid :
ctx . errNode ( n , "declarator has incomplete type" )
}
if n . IsTypedefName {
if k , ok := complexTypedefs [ n . Name ( ) ] ; ok {
abi := ctx . cfg . ABI
t := n . typ . Alias ( )
t . setKind ( k )
abi . types [ k ] = t
abi . Types [ k ] = ABIType { Size : t . Size ( ) , Align : t . Align ( ) , FieldAlign : t . FieldAlign ( ) }
}
}
switch expr , ok := n . AttributeSpecifierList . Has ( idVectorSize , idVectorSize2 ) ; {
case ok :
n . vectorize ( ctx , expr )
default :
switch x := td . ( type ) {
case * DeclarationSpecifiers :
for ; x != nil ; x = x . DeclarationSpecifiers {
if expr , ok := x . AttributeSpecifier . Has ( idVectorSize , idVectorSize2 ) ; ok {
n . vectorize ( ctx , expr )
break
}
}
}
}
return n . typ
}
func ( n * Declarator ) vectorize ( ctx * context , expr * ExpressionList ) {
dst := & n . typ
elem := n . typ
switch n . typ . Kind ( ) {
case Function :
dst = & n . typ . ( * functionType ) . result
elem = n . typ . Result ( )
}
sz := expr . vectorSize ( ctx )
if sz == 0 {
sz = elem . Size ( )
}
if elem . Size ( ) == 0 {
ctx . errNode ( expr , "vector element has zero size" )
return
}
if sz % elem . Size ( ) != 0 {
ctx . errNode ( expr , "vector size must be a multiple of the base size" )
}
b := n . typ . base ( )
b . size = sz
b . kind = byte ( Vector )
* dst = & vectorType {
typeBase : b ,
elem : elem ,
length : sz / elem . Size ( ) ,
}
}
func ( n * ExpressionList ) vectorSize ( ctx * context ) ( r uintptr ) {
if n . ExpressionList != nil {
ctx . errNode ( n , "expected single expression" )
return 0
}
switch x := n . AssignmentExpression . Operand . Value ( ) . ( type ) {
case Int64Value :
if x <= 0 {
ctx . errNode ( n , "expected integer greater than zero" )
return 0
}
r = uintptr ( x )
case Uint64Value :
r = uintptr ( x )
case nil :
ctx . errNode ( n , "expected constant expression" )
r = 0
default :
panic ( todo ( "%T" , x ) )
}
if bits . OnesCount64 ( uint64 ( r ) ) != 1 {
ctx . errNode ( n , "expected a power of two" )
r = 0
}
return r
}
func ( n * DirectDeclarator ) check ( ctx * context , typ Type ) Type {
if n == nil {
return noType
}
switch n . Case {
case DirectDeclaratorIdent : // IDENTIFIER Asm
n . Asm . check ( ctx )
return typ
case DirectDeclaratorDecl : // '(' AttributeSpecifierList Declarator ')'
n . AttributeSpecifierList . check ( ctx , typ . baseP ( ) )
return n . Declarator . check ( ctx , noTypeDescriptor , typ , false )
case DirectDeclaratorArr : // DirectDeclarator '[' TypeQualifiers AssignmentExpression ']'
return n . DirectDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , true , false ) )
case DirectDeclaratorStaticArr : // DirectDeclarator '[' "static" TypeQualifiers AssignmentExpression ']'
return n . DirectDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , false , false ) )
case DirectDeclaratorArrStatic : // DirectDeclarator '[' TypeQualifiers "static" AssignmentExpression ']'
return n . DirectDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , n . AssignmentExpression , false , false ) )
case DirectDeclaratorStar : // DirectDeclarator '[' TypeQualifiers '*' ']'
return n . DirectDeclarator . check ( ctx , checkArray ( ctx , & n . Token , typ , nil , true , true ) )
case DirectDeclaratorFuncParam : // DirectDeclarator '(' ParameterTypeList ')'
ft := & functionType { typeBase : typeBase { kind : byte ( Function ) } , result : typ }
if typ != nil && typ . Inline ( ) {
ft . typeBase . flags = fInline
}
n . ParameterTypeList . check ( ctx , ft )
return n . DirectDeclarator . check ( ctx , ft )
case DirectDeclaratorFuncIdent : // DirectDeclarator '(' IdentifierList ')'
ft := & functionType { typeBase : typeBase { kind : byte ( Function ) } , result : typ , paramList : n . IdentifierList . check ( ctx ) }
if typ != nil && typ . Inline ( ) {
ft . typeBase . flags = fInline
}
if n . idListNoDeclList {
n . checkIdentList ( ctx , ft )
}
return n . DirectDeclarator . check ( ctx , ft )
}
panic ( internalErrorf ( "%v: %v" , n . Position ( ) , n . Case ) )
}
func ( n * DirectDeclarator ) checkIdentList ( ctx * context , ft * functionType ) {
s := n . paramScope
for _ , nm := range ft . paramList {
d := s [ nm ] [ 0 ] . ( * Declarator )
d . check ( ctx , noTypeDescriptor , ctx . cfg . ABI . Type ( Int ) , false )
ft . params = append ( ft . params , & Parameter { d , d . Type ( ) } )
}
}
func checkArray ( ctx * context , n Node , typ Type , expr * AssignmentExpression , exprIsOptional , noExpr bool ) Type { //TODO pass and use typeQualifiers
if typ == nil {
ctx . errNode ( n , "array of invalid or incomplete type" )
return noType
}
b := typ . base ( )
b . align = byte ( typ . Align ( ) )
b . fieldAlign = byte ( typ . FieldAlign ( ) )
b . kind = byte ( Array )
switch {
case expr != nil && noExpr :
panic ( todo ( "" ) )
case expr != nil :
op := expr . check ( ctx , false )
if op . Type ( ) . Kind ( ) == Invalid {
return noType
}
if ! op . Type ( ) . IsIntegerType ( ) {
//TODO report err
return noType
}
var length uintptr
var vla bool
var vlaExpr * AssignmentExpression
switch x := op . Value ( ) . ( type ) {
case nil :
vla = true
vlaExpr = expr
case Int64Value :
length = uintptr ( x )
case Uint64Value :
length = uintptr ( x )
}
switch {
case vla :
b . size = ctx . cfg . ABI . Types [ Ptr ] . Size
default :
if typ . IsIncomplete ( ) {
//TODO report error
return noType
}
b . size = length * typ . Size ( )
}
return & arrayType { typeBase : b , decay : ctx . cfg . ABI . Ptr ( n , typ ) , elem : typ , length : length , vla : vla , expr : vlaExpr }
case noExpr :
// nop
case ! exprIsOptional :
panic ( todo ( "" ) )
}
b . flags |= fIncomplete
return & arrayType { typeBase : b , decay : ctx . cfg . ABI . Ptr ( n , typ ) , elem : typ }
}
func ( n * IdentifierList ) check ( ctx * context ) ( r [ ] StringID ) {
for ; n != nil ; n = n . IdentifierList {
tok := n . Token2 . Value
if tok == 0 {
tok = n . Token . Value
}
r = append ( r , tok )
}
return r
}
func ( n * Asm ) check ( ctx * context ) {
if n == nil {
return
}
n . AsmQualifierList . check ( ctx )
n . AsmArgList . check ( ctx )
}
func ( n * AsmArgList ) check ( ctx * context ) {
for ; n != nil ; n = n . AsmArgList {
n . AsmExpressionList . check ( ctx )
}
}
func ( n * AsmExpressionList ) check ( ctx * context ) {
if ctx . cfg . DoNotTypecheckAsm {
return
}
for ; n != nil ; n = n . AsmExpressionList {
n . AsmIndex . check ( ctx )
n . AssignmentExpression . check ( ctx , true )
}
}
func ( n * AsmIndex ) check ( ctx * context ) {
if n == nil {
return
}
n . Expression . check ( ctx , true )
}
func ( n * AsmQualifierList ) check ( ctx * context ) {
for ; n != nil ; n = n . AsmQualifierList {
n . AsmQualifier . check ( ctx )
}
}
func ( n * AsmQualifier ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case AsmQualifierVolatile : // "volatile"
//TODO
case AsmQualifierInline : // "inline"
//TODO
case AsmQualifierGoto : // "goto"
//TODO
default :
panic ( todo ( "" ) )
}
}
func ( n * AttributeSpecifierList ) check ( ctx * context , t * typeBase ) ( a [ ] * AttributeSpecifier ) {
for ; n != nil ; n = n . AttributeSpecifierList {
a = append ( a , n . AttributeSpecifier . check ( ctx , t ) )
}
return a
}
func ( n * AttributeSpecifier ) check ( ctx * context , t * typeBase ) * AttributeSpecifier {
if n == nil {
return nil
}
n . AttributeValueList . check ( ctx , t )
return n
}
func ( n * AttributeValueList ) check ( ctx * context , t * typeBase ) {
for ; n != nil ; n = n . AttributeValueList {
n . AttributeValue . check ( ctx , t )
}
}
func ( n * AttributeValue ) check ( ctx * context , t * typeBase ) {
if n == nil {
return
}
switch n . Case {
case AttributeValueIdent : // IDENTIFIER
if n . Token . Value == idPacked && t != nil {
t . flags |= fPacked
}
case AttributeValueExpr : // IDENTIFIER '(' ExpressionList ')'
v := ctx . cfg . ignoreErrors
ctx . cfg . ignoreErrors = true
defer func ( ) { ctx . cfg . ignoreErrors = v } ( )
n . ExpressionList . check ( ctx , false )
if n . Token . Value == idAligned && n . ExpressionList != nil && t != nil {
switch x := n . ExpressionList . AssignmentExpression . Operand . Value ( ) . ( type ) {
case Int64Value :
t . setAligned ( int ( x ) )
switch t . Kind ( ) {
case Struct , Union :
ctx . structs [ StructInfo { Size : t . Size ( ) , Align : t . Align ( ) } ] = struct { } { }
}
}
}
default :
panic ( todo ( "" ) )
}
}
func ( n * ExpressionList ) check ( ctx * context , isAsmArg bool ) {
for ; n != nil ; n = n . ExpressionList {
n . AssignmentExpression . check ( ctx , isAsmArg )
}
}
func ( n * DeclarationSpecifiers ) check ( ctx * context , inUnion bool ) ( r Type , inline , noret bool ) {
n0 := n
typ := & typeBase { }
for ; n != nil ; n = n . DeclarationSpecifiers {
switch n . Case {
case DeclarationSpecifiersStorage : // StorageClassSpecifier DeclarationSpecifiers
n . StorageClassSpecifier . check ( ctx , n )
case DeclarationSpecifiersTypeSpec : // TypeSpecifier DeclarationSpecifiers
n . TypeSpecifier . check ( ctx , typ , inUnion )
case DeclarationSpecifiersTypeQual : // TypeQualifier DeclarationSpecifiers
n . TypeQualifier . check ( ctx , typ )
case DeclarationSpecifiersFunc : // FunctionSpecifier DeclarationSpecifiers
if n . FunctionSpecifier == nil {
break
}
switch n . FunctionSpecifier . Case {
case FunctionSpecifierInline : // "inline"
inline = true
case FunctionSpecifierNoreturn : // "_Noreturn"
noret = true
default :
panic ( todo ( "" ) )
}
case DeclarationSpecifiersAlignSpec : // AlignmentSpecifier DeclarationSpecifiers
n . AlignmentSpecifier . check ( ctx )
case DeclarationSpecifiersAttribute : // AttributeSpecifier DeclarationSpecifiers
n . AttributeSpecifier . check ( ctx , typ )
default :
panic ( todo ( "" ) )
}
}
r = typ . check ( ctx , n0 , true )
return r , inline , noret
}
func ( n * AlignmentSpecifier ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case AlignmentSpecifierAlignasType : // "_Alignas" '(' TypeName ')'
n . TypeName . check ( ctx , false , false , nil )
//TODO actually set the alignment
case AlignmentSpecifierAlignasExpr : // "_Alignas" '(' ConstantExpression ')'
n . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false )
//TODO actually set the alignment
default :
panic ( todo ( "" ) )
}
}
func ( n * StorageClassSpecifier ) check ( ctx * context , ds * DeclarationSpecifiers ) {
if n == nil {
return
}
switch n . Case {
case StorageClassSpecifierTypedef : // "typedef"
ds . class |= fTypedef
case StorageClassSpecifierExtern : // "extern"
ds . class |= fExtern
case StorageClassSpecifierStatic : // "static"
ds . class |= fStatic
case StorageClassSpecifierAuto : // "auto"
ds . class |= fAuto
case StorageClassSpecifierRegister : // "register"
ds . class |= fRegister
case StorageClassSpecifierThreadLocal : // "_Thread_local"
ds . class |= fThreadLocal
default :
panic ( todo ( "" ) )
}
c := bits . OnesCount ( uint ( ds . class & ( fTypedef | fExtern | fStatic | fAuto | fRegister | fThreadLocal ) ) )
if c == 1 {
return
}
// [2], 6.7.1, 2
if c == 2 && ds . class & fThreadLocal != 0 {
if ds . class & ( fStatic | fExtern ) != 0 {
return
}
}
ctx . errNode ( n , "at most, one storage-class specifier may be given in the declaration specifiers in a declaration" )
}
// DeclarationSpecifiers Declarator DeclarationList CompoundStatement
func ( n * FunctionDefinition ) checkDeclarator ( ctx * context ) {
if n == nil {
return
}
n . Declarator . fnDef = true
n . Declarator . funcDefinition = n
ctx . checkFn = n
typ , inline , noret := n . DeclarationSpecifiers . check ( ctx , false )
typ = n . Declarator . check ( ctx , n . DeclarationSpecifiers , typ , true )
typ . setFnSpecs ( inline , noret )
ctx . checkFn = nil
n . DeclarationList . checkFn ( ctx , typ , n . Declarator . ParamScope ( ) )
}
func ( n * DeclarationList ) checkFn ( ctx * context , typ Type , s Scope ) {
if n == nil {
return
}
n . check ( ctx )
ft , ok := typ . ( * functionType )
if ! ok {
return
}
if ft . params != nil {
//TODO report error
return
}
if len ( ft . paramList ) == 0 {
//TODO report error
return
}
m := make ( map [ StringID ] int , len ( ft . paramList ) )
for i , v := range ft . paramList {
if _ , ok := m [ v ] ; ok {
ctx . errNode ( n , "duplicate parameter: %s" , v )
continue
}
m [ v ] = i
}
params := make ( [ ] * Parameter , len ( m ) )
i := 0
for ; n != nil ; n = n . DeclarationList {
for n := n . Declaration . InitDeclaratorList ; n != nil ; n = n . InitDeclaratorList {
n := n . InitDeclarator
switch n . Case {
case InitDeclaratorDecl : // Declarator AttributeSpecifierList
nm := n . Declarator . Name ( )
n . Declarator . IsParameter = true
switch x , ok := m [ nm ] ; {
case ok :
params [ x ] = & Parameter { d : n . Declarator , typ : n . Declarator . Type ( ) }
i ++
default :
//TODO report error
}
case InitDeclaratorInit : // Declarator AttributeSpecifierList '=' Initializer
//TODO report error
return
default :
panic ( todo ( "" ) )
}
}
}
for i , v := range params {
if v != nil {
continue
}
nm := ft . paramList [ i ]
d := & Declarator {
DirectDeclarator : & DirectDeclarator {
Case : DirectDeclaratorIdent ,
Token : Token { Rune : IDENTIFIER , Value : nm } ,
} ,
IsParameter : true ,
Linkage : None ,
StorageClass : Automatic ,
typ : ctx . cfg . ABI . Type ( Int ) ,
}
s . declare ( nm , d )
params [ i ] = & Parameter { d , d . typ }
}
ft . params = params
}
func ( n * CompoundStatement ) check ( ctx * context ) Operand {
n . Operand = n . BlockItemList . check ( ctx )
return n . Operand
}
func ( n * BlockItemList ) check ( ctx * context ) ( r Operand ) {
r = noOperand
var last * BlockItem
for ; n != nil ; n = n . BlockItemList {
last = n . BlockItem
r = n . BlockItem . check ( ctx )
}
if last != nil {
last . Last = true
}
return r
}
func ( n * BlockItem ) check ( ctx * context ) Operand {
if n == nil {
return noOperand
}
switch n . Case {
case BlockItemDecl : // Declaration
n . Declaration . check ( ctx , false )
case BlockItemStmt : // Statement
return n . Statement . check ( ctx )
case BlockItemLabel : // LabelDeclaration
n . LabelDeclaration . check ( ctx )
case BlockItemFuncDef : // DeclarationSpecifiers Declarator CompoundStatement
ctxClosure := ctx . closure
ctx . closure = nil
ctxCheckFn := ctx . checkFn
fn := & FunctionDefinition {
DeclarationSpecifiers : n . DeclarationSpecifiers ,
Declarator : n . Declarator ,
CompoundStatement : n . CompoundStatement ,
}
n . fn = fn
ctx . checkFn = fn
n . CompoundStatement . scope . declare ( idClosure , n )
fn . checkDeclarator ( ctx )
ctxCapture := ctx . capture
ctx . capture = true
fn . checkBody ( ctx )
n . closure = ctx . closure
ctx . capture = ctxCapture
delete ( n . CompoundStatement . scope , idClosure )
ctx . checkFn = ctxCheckFn
ctx . closure = ctxClosure
case BlockItemPragma : // PragmaSTDC
n . PragmaSTDC . check ( ctx )
default :
panic ( todo ( "" ) )
}
return noOperand
}
func ( n * LabelDeclaration ) check ( ctx * context ) {
if n == nil {
return
}
n . IdentifierList . check ( ctx )
}
func ( n * Statement ) check ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . Operand = noOperand
switch n . Case {
case StatementLabeled : // LabeledStatement
n . LabeledStatement . check ( ctx )
case StatementCompound : // CompoundStatement
n . Operand = n . CompoundStatement . check ( ctx )
case StatementExpr : // ExpressionStatement
n . Operand = n . ExpressionStatement . check ( ctx )
case StatementSelection : // SelectionStatement
n . SelectionStatement . check ( ctx )
case StatementIteration : // IterationStatement
n . IterationStatement . check ( ctx )
case StatementJump : // JumpStatement
n . JumpStatement . check ( ctx )
case StatementAsm : // AsmStatement
n . AsmStatement . check ( ctx )
default :
panic ( todo ( "" ) )
}
return n . Operand
}
func ( n * JumpStatement ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case JumpStatementGoto : // "goto" IDENTIFIER ';'
n . context = ctx . breakCtx
if ctx . checkFn . Gotos == nil {
ctx . checkFn . Gotos = map [ StringID ] * JumpStatement { }
}
ctx . checkFn . Gotos [ n . Token2 . Value ] = n
case JumpStatementGotoExpr : // "goto" '*' Expression ';'
n . Expression . check ( ctx , false )
//TODO
case JumpStatementContinue : // "continue" ';'
n . context = ctx . breakCtx
if ctx . continues <= 0 {
panic ( n . Position ( ) . String ( ) )
}
//TODO
case JumpStatementBreak : // "break" ';'
n . context = ctx . breakCtx
if ctx . breaks <= 0 {
panic ( n . Position ( ) . String ( ) )
}
//TODO
case JumpStatementReturn : // "return" Expression ';'
n . context = ctx . breakCtx
op := n . Expression . check ( ctx , false )
if op . Type ( ) . IsComplexType ( ) {
ctx . checkFn . ReturnComplexExpr = append ( ctx . checkFn . ReturnComplexExpr , n . Expression )
}
default :
panic ( todo ( "" ) )
}
}
func ( n * IterationStatement ) check ( ctx * context ) {
if n == nil {
return
}
sv := ctx . breakCtx
ctx . breakCtx = n
defer func ( ) { ctx . breakCtx = sv } ( )
switch n . Case {
case IterationStatementWhile : // "while" '(' Expression ')' Statement
n . Expression . check ( ctx , false )
ctx . breaks ++
ctx . continues ++
n . Statement . check ( ctx )
ctx . breaks --
ctx . continues --
case IterationStatementDo : // "do" Statement "while" '(' Expression ')' ';'
ctx . breaks ++
ctx . continues ++
n . Statement . check ( ctx )
ctx . breaks --
ctx . continues --
n . Expression . check ( ctx , false )
case IterationStatementFor : // "for" '(' Expression ';' Expression ';' Expression ')' Statement
n . Expression . check ( ctx , false )
n . Expression2 . check ( ctx , false )
n . Expression3 . check ( ctx , false )
ctx . breaks ++
ctx . continues ++
n . Statement . check ( ctx )
ctx . breaks --
ctx . continues --
case IterationStatementForDecl : // "for" '(' Declaration Expression ';' Expression ')' Statement
n . Declaration . check ( ctx , false )
n . Expression . check ( ctx , false )
n . Expression2 . check ( ctx , false )
ctx . breaks ++
ctx . continues ++
n . Statement . check ( ctx )
ctx . breaks --
ctx . continues --
default :
panic ( todo ( "" ) )
}
}
func ( n * SelectionStatement ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case SelectionStatementIf : // "if" '(' Expression ')' Statement
n . Expression . check ( ctx , false )
n . Statement . check ( ctx )
case SelectionStatementIfElse : // "if" '(' Expression ')' Statement "else" Statement
n . Expression . check ( ctx , false )
n . Statement . check ( ctx )
n . Statement2 . check ( ctx )
if ! n . Expression . Operand . Type ( ) . IsScalarType ( ) {
//TODO report err
break
}
case SelectionStatementSwitch : // "switch" '(' Expression ')' Statement
if n == nil {
return
}
sv := ctx . breakCtx
ctx . breakCtx = n
defer func ( ) { ctx . breakCtx = sv } ( )
op := n . Expression . check ( ctx , false )
n . promote = op . integerPromotion ( ctx , n ) . Type ( )
cp := ctx . casePromote
ctx . casePromote = n . promote
cs := ctx . cases
ctx . cases = nil
ctx . switches ++
ctx . breaks ++
n . Statement . check ( ctx )
ctx . breaks --
ctx . switches --
n . cases = ctx . cases
ctx . cases = cs
ctx . casePromote = cp
default :
panic ( todo ( "" ) )
}
}
func ( n * ExpressionStatement ) check ( ctx * context ) Operand {
if n == nil {
return noOperand
}
n . AttributeSpecifierList . check ( ctx , nil )
return n . Expression . check ( ctx , false )
}
func ( n * LabeledStatement ) check ( ctx * context ) {
if n == nil {
return
}
switch n . Case {
case LabeledStatementLabel : // IDENTIFIER ':' AttributeSpecifierList Statement
if ctx . checkFn . Labels == nil {
ctx . checkFn . Labels = map [ StringID ] * LabeledStatement { }
}
if _ , ok := ctx . checkFn . Labels [ n . Token . Value ] ; ok {
//TODO report redeclared
}
ctx . checkFn . Labels [ n . Token . Value ] = n
n . AttributeSpecifierList . check ( ctx , nil )
n . Statement . check ( ctx )
case LabeledStatementCaseLabel : // "case" ConstantExpression ':' Statement
if ctx . switches <= 0 {
//TODO report error
break
}
switch op := n . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false ) ; op . Value ( ) . ( type ) {
case Int64Value , Uint64Value :
if t := ctx . casePromote ; t . Kind ( ) != Invalid {
n . ConstantExpression . Operand = op . convertTo ( ctx , n , t )
break
}
//TODO report error
default :
//TODO report error
}
ctx . cases = append ( ctx . cases , n )
n . Statement . check ( ctx )
case LabeledStatementRange : // "case" ConstantExpression "..." ConstantExpression ':' Statement
if ctx . switches <= 0 {
//TODO report error
break
}
switch n . ConstantExpression . check ( ctx , ctx . mode | mIntConstExpr , false ) . Value ( ) . ( type ) {
case Int64Value , Uint64Value :
// ok
default :
//TODO report error
}
switch n . ConstantExpression2 . check ( ctx , ctx . mode | mIntConstExpr , false ) . Value ( ) . ( type ) {
case Int64Value , Uint64Value :
// ok
default :
//TODO report error
}
ctx . cases = append ( ctx . cases , n )
n . Statement . check ( ctx )
case LabeledStatementDefault : // "default" ':' Statement
if ctx . switches <= 0 {
//TODO report error
break
}
ctx . cases = append ( ctx . cases , n )
n . Statement . check ( ctx )
default :
panic ( todo ( "" ) )
}
}
func ( n * DeclarationList ) check ( ctx * context ) {
for ; n != nil ; n = n . DeclarationList {
n . Declaration . check ( ctx , false )
}
}
func setAddressTaken ( n Node , d * Declarator , s string ) {
d . AddressTaken = true
// fmt.Printf("%v: %s, type %v (%v, %v), declared at %v, AddressTaken = true: %v\n",
// n.Position(), d.Name(), d.Type(), d.Type().Kind(), d.Type().Size(), d.Position(), s,
// ) //TODO-
}
// Dump returns a debug form of n.
func ( n * Initializer ) Dump ( ) string {
var b strings . Builder
f := strutil . IndentFormatter ( & b , "\t" )
n . dump ( f )
return b . String ( )
}
func pos ( n Node ) ( r token . Position ) {
if n == nil {
return r
}
r = token . Position ( n . Position ( ) )
if r . IsValid ( ) {
r . Filename = filepath . Base ( r . Filename )
}
return r
}
func ( n * Initializer ) dump ( f strutil . Formatter ) {
list := n . List ( )
if len ( list ) != 0 {
for i , v := range list {
f . Format ( "Initializer.List() #%d/%d: %v: off %v type %v" , i , len ( list ) , pos ( v ) , v . Offset , v . Type ( ) )
if fld := v . FirstDesignatorField ( ) ; fld != nil {
f . Format ( " [FirstDesignatorField %q]" , fld . Name ( ) )
}
f . Format ( "\n" )
}
}
if f0 := n . FirstDesignatorField ( ) ; f0 != nil {
f . Format ( "[FirstDesignatorField: %q, index %v, off %v, type %v] " , f0 . Name ( ) , f0 . Index ( ) , n . Offset , n . Type ( ) . Alias ( ) )
}
switch n . Case {
case InitializerExpr : // AssignmentExpression
if op := n . AssignmentExpression . Operand ; op != nil {
n . isConst = op . IsConst ( )
n . isZero = op . IsZero ( )
}
var t Type
if n . AssignmentExpression != nil && n . AssignmentExpression . Operand != nil {
t = n . AssignmentExpression . Operand . Type ( )
}
f . Format ( "%v: %T@%[2]p, .Case %v, off %v, type %v\n" , pos ( n ) , n , n . Case , n . Offset , t . Alias ( ) )
case InitializerInitList : // '{' InitializerList ',' '}'
n . InitializerList . dump ( f )
default :
panic ( todo ( "%v:" , n . Position ( ) ) )
}
}
// Dump returns a debug form of n.
func ( n * InitializerList ) Dump ( ) string {
var b strings . Builder
f := strutil . IndentFormatter ( & b , "\t" )
n . dump ( f )
return b . String ( )
}
func ( n * InitializerList ) dump ( f strutil . Formatter ) {
if n == nil {
f . Format ( "<nil>" )
return
}
f . Format ( "%v: %T@%[2]p, len(.List()) %v {%i\n" , pos ( n ) , n , len ( n . List ( ) ) )
list := n . List ( )
for ; n != nil ; n = n . InitializerList {
n . Designation . dump ( f )
n . Initializer . dump ( f )
}
for i , v := range list {
f . Format ( "InitializerList.List() #%d/%d:" , i , len ( list ) )
v . dump ( f )
}
f . Format ( "%u}\n" )
}
func ( n * Designation ) dump ( f strutil . Formatter ) {
if n == nil {
return
}
cnt := 0
designatorField2 := false
for n := n . DesignatorList ; n != nil ; n = n . DesignatorList {
n . Designator . dump ( f )
if n . Designator . Case == DesignatorField2 {
designatorField2 = true
}
cnt ++
}
if cnt > 1 || ! designatorField2 {
f . Format ( " = " )
}
}
func ( n * Designator ) dump ( f strutil . Formatter ) {
switch n . Case {
case DesignatorIndex : // '[' ConstantExpression ']'
f . Format ( "[%v]" , n . ConstantExpression . Operand . Value ( ) )
case DesignatorField : // '.' IDENTIFIER
f . Format ( ".%s" , n . Token2 . Value )
case DesignatorField2 : // IDENTIFIER ':'
f . Format ( "%s:" , n . Token . Value )
default :
panic ( todo ( "" ) )
}
}