Skip to content

Commit

Permalink
Refactor ITypeSymbol to also store the array dimension if any, and th…
Browse files Browse the repository at this point in the history
…e relevant modifier flags such as 'Const' and 'Out' etc.

These changes make it easier to validate type passing where 'Out', 'Coerce', or 'Const' are relevant.

This commit also marks many more symbols as 'Const' where it makes sense.
  • Loading branch information
EliotVU committed Jun 28, 2024
1 parent 9c60d3f commit e19c03b
Show file tree
Hide file tree
Showing 14 changed files with 286 additions and 160 deletions.
2 changes: 1 addition & 1 deletion server/src/UC/Symbols/DefaultPropertiesBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ModifierFlags } from './ModifierFlags';

export class UCDefaultPropertiesBlock extends UCStructSymbol {
override kind = UCSymbolKind.DefaultPropertiesBlock;
override modifiers = ModifierFlags.NoDeclaration;
override modifiers = ModifierFlags.ReadOnly | ModifierFlags.NoDeclaration;

override getCompletionSymbols<C extends ISymbol>(document: UCDocument, context: ContextKind, kinds?: UCSymbolKind | undefined): C[] {
const outerClass = getContext<UCClassSymbol>(this, UCSymbolKind.Class);
Expand Down
2 changes: 2 additions & 0 deletions server/src/UC/Symbols/EnumSymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import {
UCSymbolKind,
UCTypeKind,
} from './';
import { ModifierFlags } from './ModifierFlags';

export class UCEnumSymbol extends UCStructSymbol {
override kind = UCSymbolKind.Enum;
override modifiers = ModifierFlags.ReadOnly;

declare public extendsType?: undefined;

Expand Down
2 changes: 2 additions & 0 deletions server/src/UC/Symbols/FieldSymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export abstract class UCFieldSymbol extends UCObjectSymbol {
/**
* Returns true if this property is declared as a static array type (false if it's dynamic!).
* Note that this property will be seen as a static array even if the @arrayDim value is invalid.
*
* @deprecated
*/
isFixedArray(): boolean {
return (this.modifiers & ModifierFlags.WithDimension) === ModifierFlags.WithDimension;
Expand Down
12 changes: 10 additions & 2 deletions server/src/UC/Symbols/IntrinsicArrayIterator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ import { ModifierFlags } from './ModifierFlags';
export const ArrayIterator = new UCMethodLikeSymbol(toName('Iterator'));
ArrayIterator.modifiers |= ModifierFlags.Intrinsic | ModifierFlags.ReadOnly | ModifierFlags.NoDeclaration;
ArrayIterator.specifiers |= MethodFlags.Iterator | MethodFlags.Static | MethodFlags.Final;
const OutParam = new UCParamSymbol({ name: toName('Element'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticMetaType);
const OutParam = new UCParamSymbol(
{ name: toName('Element'), range: DEFAULT_RANGE },
DEFAULT_RANGE,
Object.create(StaticMetaType, { flags: { value: ModifierFlags.Out } })
);
OutParam.modifiers |= ModifierFlags.Out;
ArrayIterator.addSymbol(OutParam);
const IndexParam = new UCParamSymbol({ name: toName('Index'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticIntType);
const IndexParam = new UCParamSymbol(
{ name: toName('Index'), range: DEFAULT_RANGE },
DEFAULT_RANGE,
Object.create(StaticIntType, { flags: { value: ModifierFlags.Out } })
);
IndexParam.modifiers |= ModifierFlags.Out | ModifierFlags.Optional;
ArrayIterator.addSymbol(IndexParam);
ArrayIterator.params = [OutParam, IndexParam];
21 changes: 13 additions & 8 deletions server/src/UC/Symbols/IntrinsicSymbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { toName } from '../name';
import { NAME_ARRAY, NAME_RETURNVALUE } from '../names';
import {
DEFAULT_RANGE,
StaticConstFloatType,
StaticConstIntType,
StaticDelegateType,
StaticFloatType,
StaticIntType,
Expand Down Expand Up @@ -107,21 +109,24 @@ IntrinsicArray.addSymbol(Array_SortFunction);
const ReturnValueIdentifier = { name: NAME_RETURNVALUE, range: DEFAULT_RANGE };

const VectorReturnValue = new UCParamSymbol(ReturnValueIdentifier, DEFAULT_RANGE, StaticVectorType);
VectorReturnValue.modifiers |= ModifierFlags.ReturnParam | ModifierFlags.Out;
const RotatorReturnValue = new UCParamSymbol(ReturnValueIdentifier, DEFAULT_RANGE, StaticRotatorType);
RotatorReturnValue.modifiers |= ModifierFlags.ReturnParam | ModifierFlags.Out;
const RangeReturnValue = new UCParamSymbol(ReturnValueIdentifier, DEFAULT_RANGE, StaticRangeType);
RangeReturnValue.modifiers |= ModifierFlags.ReturnParam | ModifierFlags.Out;

export const IntrinsicVectLiteral = new UCMethodLikeSymbol(toName('Vect'));
IntrinsicVectLiteral.returnValue = VectorReturnValue;

const XParam = new UCParamSymbol({ name: toName('X'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticFloatType);
const XParam = new UCParamSymbol({ name: toName('X'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstFloatType);
XParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicVectLiteral.addSymbol(XParam);

const YParam = new UCParamSymbol({ name: toName('Y'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticFloatType);
const YParam = new UCParamSymbol({ name: toName('Y'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstFloatType);
YParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicVectLiteral.addSymbol(YParam);

const ZParam = new UCParamSymbol({ name: toName('Z'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticFloatType);
const ZParam = new UCParamSymbol({ name: toName('Z'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstFloatType);
ZParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicVectLiteral.addSymbol(ZParam);

Expand All @@ -130,15 +135,15 @@ IntrinsicVectLiteral.params = [XParam, YParam, ZParam];
export const IntrinsicRotLiteral = new UCMethodLikeSymbol(toName('Rot'));
IntrinsicRotLiteral.returnValue = RotatorReturnValue;

const PitchParam = new UCParamSymbol({ name: toName('Pitch'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticIntType);
const PitchParam = new UCParamSymbol({ name: toName('Pitch'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstIntType);
PitchParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicRotLiteral.addSymbol(PitchParam);

const YawParam = new UCParamSymbol({ name: toName('Yaw'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticIntType);
const YawParam = new UCParamSymbol({ name: toName('Yaw'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstIntType);
YawParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicRotLiteral.addSymbol(YawParam);

const RollParam = new UCParamSymbol({ name: toName('Roll'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticIntType);
const RollParam = new UCParamSymbol({ name: toName('Roll'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstIntType);
RollParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicRotLiteral.addSymbol(RollParam);

Expand All @@ -147,11 +152,11 @@ IntrinsicRotLiteral.params = [PitchParam, YawParam, RollParam];
export const IntrinsicRngLiteral = new UCMethodLikeSymbol(toName('Rng'));
IntrinsicRngLiteral.returnValue = RangeReturnValue;

const MinParam = new UCParamSymbol({ name: toName('Min'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticFloatType);
const MinParam = new UCParamSymbol({ name: toName('Min'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstFloatType);
MinParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicRngLiteral.addSymbol(MinParam);

const MaxParam = new UCParamSymbol({ name: toName('Max'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticFloatType);
const MaxParam = new UCParamSymbol({ name: toName('Max'), range: DEFAULT_RANGE }, DEFAULT_RANGE, StaticConstFloatType);
MinParam.modifiers |= ModifierFlags.ReadOnly;
IntrinsicRngLiteral.addSymbol(MaxParam);

Expand Down
2 changes: 2 additions & 0 deletions server/src/UC/Symbols/MacroSymbol.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { UCFieldSymbol, UCSymbolKind } from './';
import { ModifierFlags } from './ModifierFlags';

export class UCMacroSymbol extends UCFieldSymbol {
override kind = UCSymbolKind.Macro;
override modifiers = ModifierFlags.ReadOnly;
}
3 changes: 3 additions & 0 deletions server/src/UC/Symbols/ModifierFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,7 @@ export const enum ModifierFlags {

// A private method can however be re-defined!
NonOverridable = Private | Intrinsic,

/** Flags that have an impact on type checking. */
TypeFlags = Out | Coerce | Ref | ReadOnly | WithDimension | ReturnParam
}
74 changes: 42 additions & 32 deletions server/src/UC/Symbols/PropertySymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ export class UCPropertySymbol extends UCFieldSymbol {
// The type if specified, i.e. "var Object Outer;" Object here is represented by @type, including the resolved symbol.
public type: ITypeSymbol;

// The array dimension if specified, undefined if @arrayDimRef is truthy.
/**
* @deprecated use getArrayDimSize, also see ITypeSymbol.ArrayDimension
*/
public arrayDim?: number;

// Array dimension is statically based on a declared symbol, such as a const or enum member.
Expand All @@ -39,38 +41,15 @@ export class UCPropertySymbol extends UCFieldSymbol {
this.type = type;
}

/**
* @deprecated @see isArrayTypeSymbol
*/
isDynamicArray(): this is { type: UCArrayTypeSymbol } {
return (this.type?.getTypeKind() === UCTypeKind.Array);
}

/**
* Resolves and returns static array's size.
* Returns undefined if unresolved.
*/
getArrayDimSize(): number | undefined {
if (this.arrayDimRef) {
const symbol = this.arrayDimRef.getRef();
if (!symbol) {
return undefined;
}

if (isConstSymbol(symbol)) {
const value = symbol.getComputedValue();
return typeof value === 'number'
? value
: undefined;
}

if (config.generation === UCGeneration.UC3) {
if (isEnumSymbol(symbol)) {
return symbol.maxValue;
}
if (isEnumTagSymbol(symbol)) {
return symbol.value;
}
}
}
return this.arrayDim;
return this.type.arrayDimension;
}

override getTypeKind() {
Expand Down Expand Up @@ -111,9 +90,9 @@ export class UCPropertySymbol extends UCFieldSymbol {
text.push(this.type!.getTypeText());
text.push(this.getTooltipId());

if (this.isFixedArray()) {
const arrayDim = this.getArrayDimSize() ?? '';
text.push(text.pop() + `[${arrayDim}]`);
if (this.type.arrayDimension && this.type.arrayDimension > 0) {
const arrayDim = this.type.arrayDimension;
text.push(`${text.pop()}[${arrayDim}]`);
}

return text.filter(s => s).join(' ');
Expand Down Expand Up @@ -141,7 +120,38 @@ export class UCPropertySymbol extends UCFieldSymbol {
super.index(document, context);

this.type?.index(document, context);
this.arrayDimRef?.index(document, context);

if (this.arrayDimRef) {
this.arrayDimRef.index(document, context);

// TODO: Re-factor to visitor pattern that can fold any symbol.
function computeArrayDimension(type: ITypeSymbol): number | undefined {
const symbol = type.getRef();
if (!symbol) {
return undefined;
}

if (isConstSymbol(symbol)) {
const value = symbol.getComputedValue();
return typeof value === 'number'
? value
: undefined;
}

if (config.generation === UCGeneration.UC3) {
if (isEnumSymbol(symbol)) {
return symbol.maxValue;
}
if (isEnumTagSymbol(symbol)) {
return symbol.value;
}
}

return undefined;
}

this.type.arrayDimension = computeArrayDimension(this.arrayDimRef);
}
}

override accept<Result>(visitor: SymbolWalker<Result>): Result | void {
Expand Down
2 changes: 1 addition & 1 deletion server/src/UC/Symbols/ReplicationBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ModifierFlags } from './ModifierFlags';

export class UCReplicationBlock extends UCStructSymbol {
override kind = UCSymbolKind.ReplicationBlock;
override modifiers = ModifierFlags.NoDeclaration;
override modifiers = ModifierFlags.ReadOnly | ModifierFlags.NoDeclaration;

// Just return the keyword identifier.
override getTooltip(): string {
Expand Down
9 changes: 3 additions & 6 deletions server/src/UC/Symbols/StructSymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,14 @@ export function getBinaryOperatorConversionCost(
inputTypeA: ITypeSymbol, inputTypeB: ITypeSymbol
): UCConversionCost {
const operandA = operator.params![0].getType();
const coerceA = operator.params![0].modifiers & ModifierFlags.Coerce;
const operandACost = getConversionCost(inputTypeA, operandA, UCMatchFlags.Coerce * Number(coerceA !== 0));
const operandACost = getConversionCost(inputTypeA, operandA);
if (operandACost === UCConversionCost.Illegal) {
// left type is incompatible.
return UCConversionCost.Illegal;
}

const operandB = operator.params![1].getType();
const coerceB = operator.params![1].modifiers & ModifierFlags.Coerce;
const operandBCost = getConversionCost(inputTypeB, operandB, UCMatchFlags.Coerce * Number(coerceB !== 0));
const operandBCost = getConversionCost(inputTypeB, operandB);
if (operandBCost === UCConversionCost.Illegal) {
// right type is incompatible.
return UCConversionCost.Illegal;
Expand All @@ -316,8 +314,7 @@ export function getUnaryOperatorConversionCost(
inputType: ITypeSymbol
): UCConversionCost {
const operandA = operator.params![0].getType();
const coerceA = operator.params![0].modifiers & ModifierFlags.Coerce;
const operandACost = getConversionCost(inputType, operandA, UCMatchFlags.Coerce * Number(coerceA !== 0));
const operandACost = getConversionCost(inputType, operandA);
return operandACost;
}

Expand Down
Loading

0 comments on commit e19c03b

Please sign in to comment.