Skip to content

Commit

Permalink
refactor: Moving Context to new file
Browse files Browse the repository at this point in the history
  • Loading branch information
deleterium committed Feb 20, 2024
1 parent 0540a05 commit d360922
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 177 deletions.
179 changes: 2 additions & 177 deletions src/codeGenerator/codeGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assertNotUndefined, deepCopy } from '../repository/repository'
import { assertNotUndefined } from '../repository/repository'
import { CONTRACT } from '../typings/contractTypes'
import { AST, DECLARATION_TYPES, MEMORY_SLOT, SENTENCES } from '../typings/syntaxTypes'
import { AST, MEMORY_SLOT, SENTENCES } from '../typings/syntaxTypes'
import optimizer from './assemblyProcessor/optimizer'
import genCode from './astProcessor/genCode'

Expand All @@ -17,89 +17,6 @@ type SETUPGENCODE_ARGS = {
* @returns assembly source code
*/
export default function codeGenerator (Program: CONTRACT) {
// holds variables needed during compilation
Program.Context = {
registerInfo: [],
isTemp,
getNewRegister,
freeRegister,
latestLoopId: [],
jumpId: 0,
assemblyCode: '',
errors: '',
currFunctionIndex: -1,
currSourceLine: 0,
scopedRegisters: [],
getNewJumpID: function () {
// Any changes here, also change function auxvarsGetNewJumpID
this.jumpId++
return this.jumpId.toString(36)
},
getLatestLoopID: function () {
// error check must be in code!
return this.latestLoopId[this.latestLoopId.length - 1]
},
getLatestPureLoopID: function () {
// error check must be in code!
return this.latestLoopId.reduce((previous, current) => {
if (current.includes('loop')) {
return current
}
return previous
}, '')
},
printFreeRegisters () {
let registers = 'r0'
for (let i = 1; i < Program.Config.maxAuxVars; i++) {
if (this.scopedRegisters.findIndex(item => item === `r${i}`) === -1) {
registers += `,r${i}`
}
}
this.assemblyCode += `^comment scope ${registers}\n`
},
startScope: function (scopeName: string) {
this.scopedRegisters.push(scopeName)
if (Program.Config.verboseScope) {
this.printFreeRegisters()
}
},
stopScope: function (scopeName: string) {
let liberationNeeded: string
do {
liberationNeeded = assertNotUndefined(this.scopedRegisters.pop(), 'Internal error')
if (/^r\d$/.test(liberationNeeded)) {
const motherMemory = assertNotUndefined(Program.memory.find(obj =>
obj.asmName === liberationNeeded &&
obj.type !== 'register'
), 'Internal error')
motherMemory.address = -1
motherMemory.asmName = ''
const Reg = assertNotUndefined(this.registerInfo.find(Item => Item.Template.asmName === liberationNeeded))
Reg.inUse = false
Reg.endurance = 'Standard'
}
} while (liberationNeeded !== scopeName)
if (Program.Config.verboseScope) {
this.printFreeRegisters()
}
},
getMemoryObjectByName,
getMemoryObjectByLocation,
SentenceContext: {
isDeclaration: '',
isLeftSideOfAssignment: false,
isConstSentence: false,
isRegisterSentence: false,
hasVoidArray: false,
postOperations: '',
getAndClearPostOperations: function () {
const ret = this.postOperations
this.postOperations = ''
return ret
}
}
}

// main function for bigastCompile method, only run once.
function generateMain () {
// add Config Info
Expand Down Expand Up @@ -448,98 +365,6 @@ export default function codeGenerator (Program: CONTRACT) {
}
}

function getMemoryObjectByName (
varName: string, line: string, varDeclaration: DECLARATION_TYPES = ''
) : MEMORY_SLOT {
let MemFound: MEMORY_SLOT | undefined
if (Program.Context.currFunctionIndex >= 0) { // find function scope variable
MemFound = Program.memory.find(obj => {
return obj.name === varName && obj.scope === Program.functions[Program.Context.currFunctionIndex].name
})
}
if (MemFound === undefined) {
// do a global scope search
MemFound = Program.memory.find(obj => obj.name === varName && obj.scope === '')
}
if (MemFound === undefined) {
throw new Error(`At line: ${line}. Using variable '${varName}' before declaration.`)
}
if (MemFound.toBeRegister && MemFound.asmName === '') {
throw new Error(`At line: ${line}. Using variable '${varName}' out of scope!`)
}
if (!MemFound.isSet) {
detectAndSetNotInitialized(MemFound, line, varDeclaration !== '')
}
if (varDeclaration !== '') { // we are in declarations sentence
MemFound.isDeclared = true
return deepCopy(MemFound)
}
return deepCopy(MemFound)
}

function getMemoryObjectByLocation (loc: number|bigint|string, line: string): MEMORY_SLOT {
let addr:number
switch (typeof loc) {
case 'number': addr = loc; break
case 'string': addr = parseInt(loc, 16); break
default: addr = Number(loc)
}
const FoundMemory = Program.memory.find(obj => obj.address === addr)
if (FoundMemory === undefined) {
throw new Error(`At line: ${line}. No variable found at address '${addr}'.`)
}
if (!FoundMemory.isSet) {
detectAndSetNotInitialized(FoundMemory, line, false)
}
return deepCopy(FoundMemory)
}

function detectAndSetNotInitialized (Memory: MEMORY_SLOT, line: string, isInitialization: boolean) {
if (Program.Context.SentenceContext.isLeftSideOfAssignment || Memory.hexContent) {
Memory.isSet = true
return
}
if (isInitialization) {
return
}
Program.warnings.push(`Warning: at line ${line}. Variable '${Memory.name}' is used but not initialized.`)
Memory.isSet = true // No more warning for same variable
}

function isTemp (loc: number) : boolean {
if (loc === -1) return false
const id = Program.Context.registerInfo.find(OBJ => OBJ.Template.address === loc)
if (id === undefined) {
return false
}
if (Program.Context.scopedRegisters.find(items => items === id.Template.asmName)) {
// It is a register, but scoped. Do not mess!!!
return false
}
return true
}

function getNewRegister (line: string): MEMORY_SLOT {
const id = Program.Context.registerInfo.find(OBJ => OBJ.inUse === false)
if (id === undefined) {
throw new Error(`At line: ${line}. ` +
'No more registers available. ' +
`Increase the number with '#pragma maxAuxVars ${Program.Config.maxAuxVars + 1}' or try to reduce nested operations.`)
}
id.inUse = true
return deepCopy(id.Template)
}

function freeRegister (loc: number|undefined): void {
if (loc === undefined || loc === -1) {
return
}
const RegInfo = Program.Context.registerInfo.find(OBJ => OBJ.Template.address === loc)
if (RegInfo === undefined) return
if (RegInfo.endurance === 'Scope') return
RegInfo.inUse = false
}

/** Run to start compilation in each sentence. */
function setupGenCode (CodeGenInfo: SETUPGENCODE_ARGS): string {
CodeGenInfo.InitialAST = assertNotUndefined(CodeGenInfo.InitialAST)
Expand Down
171 changes: 171 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { GLOBAL_CONTEXT } from './codeGenerator/codeGeneratorTypes'
import { assertNotUndefined, deepCopy } from './repository/repository'
import { CONTRACT } from './typings/contractTypes'
import { DECLARATION_TYPES, MEMORY_SLOT } from './typings/syntaxTypes'

export function createContext (Program: CONTRACT) : GLOBAL_CONTEXT {
function detectAndSetNotInitialized (Memory: MEMORY_SLOT, line: string, isInitialization: boolean) {
if (Program.Context.SentenceContext.isLeftSideOfAssignment || Memory.hexContent) {
Memory.isSet = true
return
}
if (isInitialization) {
return
}
Program.Context.warnings.push(`Warning: at line ${line}. Variable '${Memory.name}' is used but not initialized.`)
Memory.isSet = true // No more warning for same variable
}

return {
registerInfo: [],
isTemp (loc: number) : boolean {
if (loc === -1) return false
const id = this.registerInfo.find(OBJ => OBJ.Template.address === loc)
if (id === undefined) {
return false
}
if (this.scopedRegisters.find(items => items === id.Template.asmName)) {
// It is a register, but scoped. Do not mess!!!
return false
}
return true
},
getNewRegister (line: string): MEMORY_SLOT {
const id = this.registerInfo.find(OBJ => OBJ.inUse === false)
if (id === undefined) {
throw new Error(`At line: ${line}. ` +
'No more registers available. ' +
`Increase the number with '#pragma maxAuxVars ${Program.Config.maxAuxVars + 1}' or try to reduce nested operations.`)
}
id.inUse = true
return deepCopy(id.Template)
},
freeRegister (loc: number|undefined): void {
if (loc === undefined || loc === -1) {
return
}
const RegInfo = this.registerInfo.find(OBJ => OBJ.Template.address === loc)
if (RegInfo === undefined) return
if (RegInfo.endurance === 'Scope') return
RegInfo.inUse = false
},
latestLoopId: [],
jumpId: 0,
assemblyCode: '',
warnings: [],
errors: '',
currFunctionIndex: -1,
currSourceLine: 0,
scopedRegisters: [],
getNewJumpID: function () {
// Any changes here, also change function auxvarsGetNewJumpID
this.jumpId++
return this.jumpId.toString(36)
},
getLatestLoopID: function () {
// error check must be in code!
return this.latestLoopId[this.latestLoopId.length - 1]
},
getLatestPureLoopID: function () {
// error check must be in code!
return this.latestLoopId.reduce((previous, current) => {
if (current.includes('loop')) {
return current
}
return previous
}, '')
},
printFreeRegisters () {
let registers = 'r0'
for (let i = 1; i < Program.Config.maxAuxVars; i++) {
if (this.scopedRegisters.findIndex(item => item === `r${i}`) === -1) {
registers += `,r${i}`
}
}
this.assemblyCode += `^comment scope ${registers}\n`
},
startScope (scopeName: string) {
this.scopedRegisters.push(scopeName)
if (Program.Config.verboseScope) {
this.printFreeRegisters()
}
},
stopScope: function (scopeName: string) {
let liberationNeeded: string
do {
liberationNeeded = assertNotUndefined(this.scopedRegisters.pop(), 'Internal error')
if (/^r\d$/.test(liberationNeeded)) {
const motherMemory = assertNotUndefined(Program.memory.find(obj =>
obj.asmName === liberationNeeded &&
obj.type !== 'register'
), 'Internal error')
motherMemory.address = -1
motherMemory.asmName = ''
const Reg = assertNotUndefined(this.registerInfo.find(Item => Item.Template.asmName === liberationNeeded))
Reg.inUse = false
Reg.endurance = 'Standard'
}
} while (liberationNeeded !== scopeName)
if (Program.Config.verboseScope) {
this.printFreeRegisters()
}
},
getMemoryObjectByName (
varName: string, line: string, varDeclaration: DECLARATION_TYPES = ''
) : MEMORY_SLOT {
let MemFound: MEMORY_SLOT | undefined
if (this.currFunctionIndex >= 0) { // find function scope variable
MemFound = Program.memory.find(obj => {
return obj.name === varName && obj.scope === Program.functions[this.currFunctionIndex].name
})
}
if (MemFound === undefined) {
// do a global scope search
MemFound = Program.memory.find(obj => obj.name === varName && obj.scope === '')
}
if (MemFound === undefined) {
throw new Error(`At line: ${line}. Using variable '${varName}' before declaration.`)
}
if (MemFound.toBeRegister && MemFound.asmName === '') {
throw new Error(`At line: ${line}. Using variable '${varName}' out of scope!`)
}
if (!MemFound.isSet) {
detectAndSetNotInitialized(MemFound, line, varDeclaration !== '')
}
if (varDeclaration !== '') { // we are in declarations sentence
MemFound.isDeclared = true
return deepCopy(MemFound)
}
return deepCopy(MemFound)
},
getMemoryObjectByLocation (loc: number|bigint|string, line: string): MEMORY_SLOT {
let addr:number
switch (typeof loc) {
case 'number': addr = loc; break
case 'string': addr = parseInt(loc, 16); break
default: addr = Number(loc)
}
const FoundMemory = Program.memory.find(obj => obj.address === addr)
if (FoundMemory === undefined) {
throw new Error(`At line: ${line}. No variable found at address '${addr}'.`)
}
if (!FoundMemory.isSet) {
detectAndSetNotInitialized(FoundMemory, line, false)
}
return deepCopy(FoundMemory)
},
SentenceContext: {
isDeclaration: '',
isLeftSideOfAssignment: false,
isConstSentence: false,
isRegisterSentence: false,
hasVoidArray: false,
postOperations: '',
getAndClearPostOperations: function () {
const ret = this.postOperations
this.postOperations = ''
return ret
}
}
}
}
3 changes: 3 additions & 0 deletions src/smartc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import assembler from './assembler/assembler'

import { PRE_TOKEN, TOKEN } from './typings/syntaxTypes'
import { CONTRACT, MACHINE_OBJECT } from './typings/contractTypes'
import { createContext } from './context'

/**
* SmartC Compiler class.
Expand Down Expand Up @@ -38,6 +39,7 @@ export class SmartC {
private readonly sourceCode
private preAssemblyCode?: string
private MachineCode?: MACHINE_OBJECT
// @ts-ignore
private Program: CONTRACT = {
sourceLines: [],
Global: {
Expand Down Expand Up @@ -75,6 +77,7 @@ export class SmartC {
this.Program.sourceLines = Options.sourceCode.split('\n')
this.language = Options.language
this.sourceCode = Options.sourceCode
this.Program.Context = createContext(this.Program)
}

/**
Expand Down

0 comments on commit d360922

Please sign in to comment.