import parseImmediate from '../utils/parseImmediate' ; export type NodeType = 'DIRECTIVE' | 'DATA' | 'LABEL' | 'OPERATION' | 'IMMEDIATE' | 'OFFSET' | 'REGISTER' | 'ADDRESS' | 'TRANSFORMED' ; export class Node { public type : NodeType ; public children : Node [ ] = [ ] ; constructor ( type ) { this . type = type ; } public add ( node ) { this . children . push ( node ) ; } public toString ( ) { return '[MIPS Node]' ; } } export class DirectiveNode extends Node { public directiveType : 'data' | 'text' ; constructor ( directiveType ) { super ( 'DIRECTIVE' ) ; this . directiveType = directiveType ; } public toString ( ) { return `.${ this . directiveType }` ; } } export class DataNode extends Node { public dataDirective : string ; public values : string [ ] ; constructor ( dataDirective , values ) { super ( 'DATA' ) ; this . dataDirective = dataDirective ; this . values = values ; } public toString ( ) { return this . values . join ( ', ' ) ; } } export class LabelNode extends Node { public name : string ; constructor ( name ) { super ( 'LABEL' ) ; this . name = name ; } public toString ( ) { return `${ this . name }:` ; } } export class RegisterNode extends Node { public name : string ; constructor ( name ) { super ( 'REGISTER' ) ; this . name = name ; } public toString ( ) { return this . name ; } } export class ImmediateNode extends Node { public value : string ; constructor ( value ) { super ( 'IMMEDIATE' ) ; this . value = value ; } public split ( ) { const val = parseImmediate ( this . value ) ; const upper = ( val & 0xffff0000 ) >>> 16 ; const lower = ( val & 0x0000ffff ) ; const ret = [ ] ; if ( upper > 0 ) { ret . push ( new ImmediateNode ( upper . toString ( ) ) ) ; } ret . push ( new ImmediateNode ( lower . toString ( ) ) ) ; return ret ; } public toString ( ) { return this . value ; } } export class OffsetNode extends Node { public offset : string ; public register : string ; constructor ( offset , register ) { super ( 'OFFSET' ) ; this . offset = offset ; this . register = register ; } public toString ( ) { return `${ this . offset }(${ this . register })` ; } } export class AddressNode extends Node { public label : string ; public partitioned : boolean ; public part : 'upper' | 'lower' ; constructor ( label ) { super ( 'ADDRESS' ) ; this . label = label ; this . partitioned = false ; } public partition ( part ) { const addr = new AddressNode ( this . label ) ; addr . partitioned = true ; addr . part = part ; return addr ; } public toString ( ) { return this . label ; } } export type ArgumentNode = RegisterNode | ImmediateNode | OffsetNode | AddressNode ; export class OperationNode extends Node { public name : string ; public args : ArgumentNode [ ] ; constructor ( name , args ) { super ( 'OPERATION' ) ; this . name = name ; this . args = args ; } public toString ( ) { return `${ this . name } ${ this . args . map ( a => a . toString ( ) ) . join ( ', ' ) }` ; } } export class Root { public data : DirectiveNode ; public text : DirectiveNode ; constructor ( ) { this . data = new DirectiveNode ( 'data' ) ; this . text = new DirectiveNode ( 'text' ) ; } } export class TransformedNode extends Node { public original : OperationNode ; constructor ( operations , original ) { super ( 'TRANSFORMED' ) ; this . children = operations ; this . original = original ; } public toString ( ) { return this . children . map ( c => c . toString ( ) ) . join ( '\n' ) ; } } export const utils = { isOperationNode : ( n ) : n is OperationNode => n . type === 'OPERATION' , isLabelNode : ( n ) : n is LabelNode => n . type === 'LABEL' , isDirectiveNode : ( n ) : n is DirectiveNode => n . type === 'DIRECTIVE' , isDataNode : ( n ) : n is DataNode => n . type === 'DATA' , isRegisterNode : ( n ) : n is RegisterNode => n . type === 'REGISTER' , isImmediateNode : ( n ) : n is ImmediateNode => n . type === 'IMMEDIATE' , isOffsetNode : ( n ) : n is OffsetNode => n . type === 'OFFSET' , isAddressNode : ( n ) : n is AddressNode => n . type === 'ADDRESS' , isTranformedNode : ( n ) : n is TransformedNode => n . type === 'TRANSFORMED' , } ;