Add IsConstant() to Expression

This commit is contained in:
Sasha Koshka 2024-04-11 20:25:16 -04:00
parent 6313992c10
commit 40d500b705
2 changed files with 74 additions and 0 deletions

View File

@ -22,6 +22,10 @@ type Expression interface {
// to conform to. The value of this does not depend on semantic
// information fields.
HasExplicitType () bool
// Constant returns true if the expression's value can be computed at
// compile time.
IsConstant () bool
expression ()
}
@ -43,6 +47,7 @@ func (*Variable) expression(){}
func (this *Variable) Position () errors.Position { return this.Pos }
func (this *Variable) Type () Type { return this.Declaration.Type() }
func (this *Variable) HasExplicitType () bool { return true }
func (this *Variable) IsConstant () bool { return false }
func (this *Variable) String () string {
return this.Name
}
@ -62,6 +67,7 @@ func (*Declaration) expression(){}
func (this *Declaration) Position () errors.Position { return this.Pos }
func (this *Declaration) Type () Type { return this.Ty }
func (this *Declaration) HasExplicitType () bool { return true }
func (this *Declaration) IsConstant () bool { return false }
func (this *Declaration) String () string {
return fmt.Sprint(this.Name, ":", this.Ty)
}
@ -88,6 +94,7 @@ func (*Call) expression(){}
func (this *Call) Position () errors.Position { return this.Pos }
func (this *Call) Type () Type { return this.Function.Signature.Return }
func (this *Call) HasExplicitType () bool { return true }
func (this *Call) IsConstant () bool { return false }
func (this *Call) String () string {
out := ""
if this.UnitNickname != "" {
@ -129,6 +136,7 @@ func (this *MethodCall) Type () Type {
}
}
func (this *MethodCall) HasExplicitType () bool { return true }
func (this *MethodCall) IsConstant () bool { return false }
func (this *MethodCall) String () string {
out := fmt.Sprint(this.Source, ".[", this.Name)
for _, argument := range this.Arguments {
@ -156,6 +164,7 @@ func (*Subscript) expression(){}
func (this *Subscript) Position () errors.Position { return this.Pos }
func (this *Subscript) Type () Type { return this.Ty }
func (this *Subscript) HasExplicitType () bool { return true }
func (this *Subscript) IsConstant () bool { return false }
func (this *Subscript) String () string {
return fmt.Sprint("[.", this.Slice, " ", this.Offset, "]")
}
@ -176,6 +185,11 @@ func (*Slice) expression(){}
func (this *Slice) Position () errors.Position { return this.Pos }
func (this *Slice) Type () Type { return this.Slice.Type() }
func (this *Slice) HasExplicitType () bool { return true }
func (this *Slice) IsConstant () bool {
return this.Slice.IsConstant() &&
this.Start.IsConstant() &&
this.End.IsConstant()
}
func (this *Slice) String () string {
out := fmt.Sprint("[\\", this.Slice, " ")
if this.Start != nil {
@ -203,6 +217,7 @@ func (*Length) expression(){}
func (this *Length) Position () errors.Position { return this.Pos }
func (this *Length) Type () Type { return this.Ty }
func (this *Length) HasExplicitType () bool { return true }
func (this *Length) IsConstant () bool { return this.Slice.IsConstant() }
func (this *Length) String () string {
return fmt.Sprint("[#", this.Slice, "]")
}
@ -225,6 +240,7 @@ func (*Dereference) expression(){}
func (this *Dereference) Position () errors.Position { return this.Pos }
func (this *Dereference) Type () Type { return this.Ty }
func (this *Dereference) HasExplicitType () bool { return true }
func (this *Dereference) IsConstant () bool { return false }
func (this *Dereference) String () string {
return fmt.Sprint("[.", this.Pointer, "]")
}
@ -249,6 +265,7 @@ func (*Reference) expression(){}
func (this *Reference) Position () errors.Position { return this.Pos }
func (this *Reference) Type () Type { return this.Ty }
func (this *Reference) HasExplicitType () bool { return true }
func (this *Reference) IsConstant () bool { return false }
func (this *Reference) String () string {
return fmt.Sprint("[@", this.Value, "]")
}
@ -266,6 +283,7 @@ func (*ValueCast) expression(){}
func (this *ValueCast) Position () errors.Position { return this.Pos }
func (this *ValueCast) Type () Type { return this.Ty }
func (this *ValueCast) HasExplicitType () bool { return true }
func (this *ValueCast) IsConstant () bool { return this.Value.IsConstant() }
func (this *ValueCast) String () string {
return fmt.Sprint("[~ ", this.Ty, this.Value, "]")
}
@ -284,6 +302,7 @@ func (*BitCast) expression(){}
func (this *BitCast) Position () errors.Position { return this.Pos }
func (this *BitCast) Type () Type { return this.Ty }
func (this *BitCast) HasExplicitType () bool { return true }
func (this *BitCast) IsConstant () bool { return this.Value.IsConstant() }
func (this *BitCast) String () string {
return fmt.Sprint("[~~ ", this.Ty, this.Value, "]")
}
@ -308,6 +327,12 @@ func (this *Operation) Type () Type { return this.Ty }
func (this *Operation) HasExplicitType () bool {
return this.Operator.ResultsInBoolean()
}
func (this *Operation) IsConstant () bool {
for _, argument := range this.Arguments {
if !argument.IsConstant() { return false }
}
return true
}
func (this *Operation) String () string {
out := fmt.Sprint("[", this.Operator)
for _, argument := range this.Arguments {
@ -338,6 +363,10 @@ func (this *Block) HasExplicitType () bool {
if len(this.Steps) == 0 { return false }
return this.Steps[len(this.Steps) - 1].HasExplicitType()
}
func (this *Block) IsConstant () bool {
if len(this.Steps) == 0 { return false }
return this.Steps[len(this.Steps) - 1].IsConstant()
}
func (this *Block) String () string {
out := "{"
for index, step := range this.Steps {
@ -367,6 +396,7 @@ func (*MemberAccess) expression(){}
func (this *MemberAccess) Position () errors.Position { return this.Pos }
func (this *MemberAccess) Type () Type { return this.Ty }
func (this *MemberAccess) HasExplicitType () bool { return true }
func (this *MemberAccess) IsConstant () bool { return this.Source.IsConstant() }
func (this *MemberAccess) String () string {
return fmt.Sprint(this.Source, ".", this.Member)
}
@ -393,6 +423,11 @@ func (this *IfElse) Type () Type { return this.Ty }
func (this *IfElse) HasExplicitType () bool {
return this.True.HasExplicitType()
}
func (this *IfElse) IsConstant () bool {
return this.Condition.IsConstant() &&
this.True.IsConstant() &&
this.False.IsConstant()
}
func (this *IfElse) String () string {
out := fmt.Sprint("if ", this.Condition, " then ", this.True)
if this.False != nil {
@ -432,6 +467,14 @@ func (this *Match) HasExplicitType () bool {
return this.Cases[0].HasExplicitType()
}
}
func (this *Match) IsConstant () bool {
if !this.Value.IsConstant() { return false }
if !this.Default.IsConstant() { return false }
for _, cas := range this.Cases {
if !cas.IsConstant () { return false }
}
return true
}
func (this *Match) String () string {
out := fmt.Sprint("match ", this.Value)
for _, cas := range this.Cases {
@ -471,6 +514,14 @@ func (this *Switch) HasExplicitType () bool {
return this.Cases[0].HasExplicitType()
}
}
func (this *Switch) IsConstant () bool {
if !this.Value.IsConstant() { return false }
if !this.Default.IsConstant() { return false }
for _, cas := range this.Cases {
if !cas.IsConstant () { return false }
}
return true
}
func (this *Switch) String () string {
out := fmt.Sprint("switch ", this.Value)
for _, cas := range this.Cases {
@ -514,6 +565,7 @@ func (this *Loop) HasExplicitType () bool {
// loop
return false
}
func (this *Loop) IsConstant () bool { return false /* TODO this may be decidable */ }
func (this *Loop) String () string {
return fmt.Sprint("loop ", this.Body)
}
@ -547,6 +599,7 @@ func (this *For) HasExplicitType () bool {
// loop
return false
}
func (this *For) IsConstant () bool { return false /* TODO this may be decidable */ }
func (this *For) String () string {
out := "for"
if this.Index != nil {
@ -571,6 +624,7 @@ func (*Break) expression(){}
func (this *Break) Position () errors.Position { return this.Pos }
func (this *Break) Type () Type { return nil }
func (this *Break) HasExplicitType () bool { return false }
func (this *Break) IsConstant () bool { return false }
func (this *Break) String () string {
if this.Value == nil {
return "[break]"
@ -597,6 +651,7 @@ func (*Return) expression(){}
func (this *Return) Position () errors.Position { return this.Pos }
func (this *Return) Type () Type { return nil }
func (this *Return) HasExplicitType () bool { return false }
func (this *Return) IsConstant () bool { return false }
func (this *Return) String () string {
if this.Value == nil {
return "[return]"
@ -619,6 +674,7 @@ func (*Assignment) expression(){}
func (this *Assignment) Position () errors.Position { return this.Pos }
func (this *Assignment) Type () Type { return nil }
func (this *Assignment) HasExplicitType () bool { return false }
func (this *Assignment) IsConstant () bool { return false }
func (this *Assignment) String () string {
return fmt.Sprint(this.Location, "=", this.Value)
}
@ -643,6 +699,7 @@ func (*Constant) expression(){}
func (this *Constant) Position () errors.Position { return this.Pos }
func (this *Constant) Type () Type { return this.Ty }
func (this *Constant) HasExplicitType () bool { return true }
func (this *Constant) IsConstant () bool { return true }
func (this *Constant) String () string {
output := ""
if this.UnitNickname != "" {

View File

@ -21,6 +21,7 @@ func (*LiteralInt) expression(){}
func (this *LiteralInt) Position () errors.Position { return this.Pos }
func (this *LiteralInt) Type () Type { return this.Ty }
func (this *LiteralInt) HasExplicitType () bool { return false }
func (this *LiteralInt) IsConstant () bool { return true }
func (this *LiteralInt) String () string {
return fmt.Sprint(this.Value)
}
@ -42,6 +43,7 @@ func (*LiteralFloat) expression(){}
func (this *LiteralFloat) Position () errors.Position { return this.Pos }
func (this *LiteralFloat) Type () Type { return this.Ty }
func (this *LiteralFloat) HasExplicitType () bool { return false }
func (this *LiteralFloat) IsConstant () bool { return true }
func (this *LiteralFloat) String () string {
return fmt.Sprint(this.Value)
}
@ -76,6 +78,7 @@ func (*LiteralString) expression(){}
func (this *LiteralString) Position () errors.Position { return this.Pos }
func (this *LiteralString) Type () Type { return this.Ty }
func (this *LiteralString) HasExplicitType () bool { return false }
func (this *LiteralString) IsConstant () bool { return true }
func (this *LiteralString) String () string {
return Quote(this.ValueUTF8)
}
@ -100,6 +103,12 @@ func (*LiteralArray) expression(){}
func (this *LiteralArray) Position () errors.Position { return this.Pos }
func (this *LiteralArray) Type () Type { return this.Ty }
func (this *LiteralArray) HasExplicitType () bool { return false }
func (this *LiteralArray) IsConstant () bool {
for _, element := range this.Elements {
if !element.IsConstant() { return false }
}
return true
}
func (this *LiteralArray) String () string {
out := "("
for index, element := range this.Elements {
@ -131,6 +140,12 @@ func (*LiteralStruct) expression(){}
func (this *LiteralStruct) Position () errors.Position { return this.Pos }
func (this *LiteralStruct) Type () Type { return this.Ty }
func (this *LiteralStruct) HasExplicitType () bool { return false }
func (this *LiteralStruct) IsConstant () bool {
for _, member := range this.Members {
if !member.Value.IsConstant() { return false }
}
return true
}
func (this *LiteralStruct) String () string {
out := "(."
for _, member := range this.Members {
@ -156,6 +171,7 @@ func (*LiteralBoolean) expression(){}
func (this *LiteralBoolean) Position () errors.Position { return this.Pos }
func (this *LiteralBoolean) Type () Type { return this.Ty }
func (this *LiteralBoolean) HasExplicitType () bool { return false }
func (this *LiteralBoolean) IsConstant () bool { return true }
func (this *LiteralBoolean) String () string {
if this.Value {
return "true"
@ -177,4 +193,5 @@ func (*LiteralNil) expression(){}
func (this *LiteralNil) Position () errors.Position { return this.Pos }
func (this *LiteralNil) Type () Type { return this.Ty }
func (this *LiteralNil) HasExplicitType () bool { return false }
func (this *LiteralNil) IsConstant () bool { return true }
func (this *LiteralNil) String () string { return "nil" }