Added some useful type checking thigns to literals

This commit is contained in:
Sasha Koshka 2022-10-04 16:19:26 -04:00
parent e2947eab8c
commit 5c286cf955
4 changed files with 177 additions and 7 deletions

View File

@ -19,6 +19,7 @@ type Argument interface {
// RuneLiteral
ToString (indent int) (output string)
canBePassedAs (what Type) (allowed bool)
}
// analyzeArgument analyzes an argument

View File

@ -14,24 +14,118 @@ func (literal IntLiteral) ToString (indent int) (output string) {
return
}
// canBePassedAs returns true if this literal can be implicitly cast to the
// specified type, and false if it can't.
func (literal IntLiteral) canBePassedAs (what Type) (allowed bool) {
// must be a singlular value
if what.length != 1 { return }
// can be passed to types that are signed numbers at a primitive level.
primitive := what.underlyingPrimitive()
switch primitive {
case
&PrimitiveF64,
&PrimitiveF32,
&PrimitiveI64,
&PrimitiveI32,
&PrimitiveI16,
&PrimitiveI8,
&PrimitiveInt:
allowed = true
}
return
}
// ToString outputs the data in the argument as a string.
func (literal UIntLiteral) ToString (indent int) (output string) {
output += doIndent(indent, fmt.Sprint("arg uint ", literal, "\n"))
return
}
// canBePassedAs returns true if this literal can be implicitly cast to the
// specified type, and false if it can't.
func (literal UIntLiteral) canBePassedAs (what Type) (allowed bool) {
// must be a singlular value
if what.length != 1 { return }
// can be passed to types that are numbers at a primitive level.
primitive := what.underlyingPrimitive()
switch primitive {
case
&PrimitiveF64,
&PrimitiveF32,
&PrimitiveI64,
&PrimitiveI32,
&PrimitiveI16,
&PrimitiveI8,
&PrimitiveInt,
&PrimitiveU64,
&PrimitiveU32,
&PrimitiveU16,
&PrimitiveU8,
&PrimitiveUInt:
allowed = true
}
return
}
// ToString outputs the data in the argument as a string.
func (literal FloatLiteral) ToString (indent int) (output string) {
output += doIndent(indent, fmt.Sprint("arg float ", literal, "\n"))
return
}
// canBePassedAs returns true if this literal can be implicitly cast to the
// specified type, and false if it can't.
func (literal FloatLiteral) canBePassedAs (what Type) (allowed bool) {
// must be a singlular value
if what.length != 1 { return }
// can be passed to types that are floats at a primitive level.
primitive := what.underlyingPrimitive()
switch primitive {
case
&PrimitiveF64,
&PrimitiveF32:
allowed = true
}
return
}
// ToString outputs the data in the argument as a string.
func (literal StringLiteral) ToString (indent int) (output string) {
output += doIndent(indent, fmt.Sprint("arg string \"", literal, "\"\n"))
return
}
// canBePassedAs returns true if this literal can be implicitly cast to the
// specified type, and false if it can't.
func (literal StringLiteral) canBePassedAs (what Type) (allowed bool) {
// can be passed to types that are numbers at a primitive level.
primitive := what.underlyingPrimitive()
switch primitive {
case
&PrimitiveF64,
&PrimitiveF32,
&PrimitiveI64,
&PrimitiveI32,
&PrimitiveI16,
&PrimitiveI8,
&PrimitiveInt,
&PrimitiveU64,
&PrimitiveU32,
&PrimitiveU16,
&PrimitiveU8,
&PrimitiveUInt:
allowed = true
}
return
}
// ToString outputs the data in the argument as a string.
func (literal RuneLiteral) ToString (indent int) (output string) {
output += doIndent(indent, fmt.Sprint("arg rune '", literal, "'\n"))

View File

@ -2,6 +2,8 @@ package analyzer
// This is a global, cannonical list of primitive and built-in types.
var PrimitiveF32 = createPrimitive("Int", Type {})
var PrimitiveF64 = createPrimitive("Int", Type {})
var PrimitiveInt = createPrimitive("Int", Type {})
var PrimitiveUInt = createPrimitive("UInt", Type {})
var PrimitiveI8 = createPrimitive("I8", Type {})

View File

@ -16,21 +16,20 @@ const (
// TypeKindVariableArray means it's an array of variable length.
TypeKindVariableArray
// TypeKindObject means it's a structured type with members.
TypeKindObject
)
// Type represents a description of a type. It must eventually point to a
// TypeSection.
type Type struct {
// one of these must be nil.
actual Section
actual *TypeSection
points *Type
mutable bool
kind TypeKind
primitiveCache *TypeSection
// if this is greater than 1, it means that this is a fixed-length array
// of whatever the type is. even if the type is a variable length array.
// because literally why not.
@ -52,8 +51,6 @@ func (what Type) ToString (indent int) (output string) {
output += " pointer"
case TypeKindVariableArray:
output += " variableArray"
case TypeKindObject:
output += " object"
}
if what.points != nil {
@ -70,6 +67,78 @@ func (what Type) ToString (indent int) (output string) {
return
}
// underlyingPrimitive returns the primitive that this type eventually inherits
// from.
func (what Type) underlyingPrimitive () (underlying *TypeSection) {
// if we have already done this operation, return the cahced result.
if what.primitiveCache != nil {
underlying = what.primitiveCache
return
}
if what.kind != TypeKindBasic {
// if we point to something, return nil because there is no void
// pointer bullshit in this language
return
}
actual := what.actual
switch actual {
case
&PrimitiveF32,
&PrimitiveF64,
&PrimitiveFunc,
&PrimitiveFace,
&PrimitiveObj,
&PrimitiveU64,
&PrimitiveU32,
&PrimitiveU16,
&PrimitiveU8,
&PrimitiveI64,
&PrimitiveI32,
&PrimitiveI16,
&PrimitiveI8,
&PrimitiveUInt,
&PrimitiveInt:
underlying = actual
return
case nil:
panic("invalid state: Type.actual is nil")
default:
// if none of the primitives matched, recurse.
underlying = actual.what.underlyingPrimitive()
return
}
}
// reduce ascends up the inheritence chain and gets the first type it finds that
// isn't basic. If the type has a clear path of inheritence to a simple
// primitive, there will be no non-basic types in the chain and this method will
// return false for reducible. If the type this method is called on is not
// basic, it itself is returned.
func (what Type) reduce () (reduced Type, reducible bool) {
reducible = true
// returns itself if it is not basic (cannot be reduced further)
if what.kind != TypeKindBasic {
reduced = what
return
}
// if we can't recurse, return false for reducible
if what.actual == nil {
reducible = false
return
}
// otherwise, recurse
reduced, reducible = what.actual.what.reduce()
return
}
// analyzeType analyzes a type specifier.
func (analyzer AnalysisOperation) analyzeType (
inputType parser.Type,
@ -93,9 +162,13 @@ func (analyzer AnalysisOperation) analyzeType (
outputType.points = &points
} else {
var bitten parser.Identifier
outputType.actual,
var actual Section
actual,
bitten,
err = analyzer.fetchSectionFromIdentifier(inputType.Name())
outputType.actual = actual.(*TypeSection)
// TODO: produce an error if this doesnt work
if bitten.Length() > 0 {
err = bitten.NewError(