From 9deb6cf4abf1584d01f62da04c1059066bd06efc Mon Sep 17 00:00:00 2001 From: chengda300 <97393284+chengda300@users.noreply.github.com> Date: Thu, 20 Feb 2025 21:56:48 +0800 Subject: [PATCH] Concurrency (#38) * Add support for randomised context switching * Remove unused import * Attempt to support go statements * Support for functions with multiple return values (#31) (#34) * Implement fmt.Print() * Update tests for println and print and implement trivial case for printf * Fix array newline not ignored between { and first element * Support for functions returning multiple values at once * Remove duplicate test cases * Improve concurrency handling to pass by value but random execution still does not work * Implement mutex * Fix defer not working inside non-main contexts * Add more test cases for mutex * Add method checking test case for mutex * Fix defer and clean up duplicate files * Remove debugging variables * Add test cases for parsing for if-else statements * Transfer test case from defer to go statement * Support other numeric types and fix go statement remnant closure on OS * Fix local browser testing error * Remove redundant functions and refactor fork to go * Fix multiple return values logic and added more test cases * Adjust logic for handling functions that return multiple values * Implement single level type declaration * Improve basic test cases for type declaration * Update logic to no longer use DeclaredNode * Refactor executor to runtime, compiler to executor, parser to compiler * Adjust logic for declared types to make literals commit to declared types instead of the other way round * Implement declared type logic check for binops * Fix uninitialised declared type variables not having zero values * Implement type declarations for functions * Implement type declaration and functions with multiple return values for arrays * Implement support for same name type across different scopes * fix whitespace removal logic for structs * Change memory layout for arrays to be contiguous * Remove dummy variables * Change memory layout for arrays to be contiguous, however does not work without explicit size declaration * Fix slices and structs --- .vscode/launch.json | 20 + package.json | 6 +- src/frontend/components/Visual/EnvNode.tsx | 2 +- src/frontend/components/Visual/VisualArea.tsx | 2 +- src/frontend/pages/Main.tsx | 6 +- src/frontend/stores/executionStore.ts | 4 +- .../.vscode/extensions.json | 3 - .../.vscode/settings.json | 3 - .../frontend/app/App.tsx | 15 - .../frontend/app/Router.tsx | 29 - .../frontend/app/index.ts | 1 - .../frontend/components/CodeIDE/CodeIDE.tsx | 123 -- .../components/CodeIDE/CodeIDEButtons.tsx | 66 - .../frontend/components/CodeIDE/index.tsx | 2 - .../frontend/components/ControlBar.tsx | 175 --- .../frontend/components/IO/TextIDE.tsx | 37 - .../frontend/components/IO/index.tsx | 22 - .../frontend/components/NavBar.tsx | 50 - .../frontend/components/Visual/EnvNode.tsx | 76 - .../frontend/components/Visual/VisualArea.tsx | 167 --- .../frontend/components/Visual/index.tsx | 1 - .../frontend/components/Visual/nodes.css | 3 - .../frontend/components/index.ts | 5 - .../frontend/pages/Main.tsx | 263 ---- .../frontend/stores/executionStore.ts | 74 - .../frontend/stores/index.ts | 1 - .../frontend/theme/index.ts | 1 - .../frontend/theme/theme.ts | 17 - .../frontend/types/cytoscape-cola/index.d.ts | 1 - .../frontend/types/global.d.ts | 1 - .../frontend/utils/error.ts | 10 - src/go-virtual-machine-main/index.tsx | 2 +- src/go-virtual-machine-main/public/cs.png | Bin 2210 -> 0 bytes src/go-virtual-machine-main/public/gopher.png | Bin 137116 -> 0 bytes .../public/gophers.png | Bin 153455 -> 0 bytes src/go-virtual-machine-main/public/index.html | 43 - .../public/manifest.json | 16 - src/go-virtual-machine-main/public/robots.txt | 3 - .../tests/array.test.ts | 182 ++- .../tests/builtin.test.ts | 13 +- .../tests/channel.test.ts | 11 + .../tests/comment.test.ts | 4 +- .../tests/concurrency.test.ts | 66 +- .../tests/declaration.test.ts | 625 ++++++++- .../tests/defer.test.ts | 78 +- .../tests/expression.test.ts | 52 + .../tests/function.test.ts | 159 ++- .../tests/heap.test.ts | 90 +- .../tests/mutex.test.ts | 140 ++ .../tests/parser.test.ts | 177 +++ .../tests/struct.test.ts | 77 ++ src/go-virtual-machine-main/tests/utility.ts | 140 +- .../tests/waitGroup.test.ts | 38 +- .../{parser => compiler}/golang_parser.js | 1231 +++++++++-------- .../{parser => compiler}/golang_parser.ts | 0 .../virtual-machine/compiler/index.ts | 38 - .../compiler/instructions/block.ts | 85 -- .../compiler/instructions/store.ts | 19 - .../{parser => compiler}/parser.peggy | 46 +- .../{parser => compiler}/parser.ts | 0 .../{parser => compiler}/tokens.ts | 0 .../{parser => compiler}/tokens/base.ts | 8 +- .../{parser => compiler}/tokens/block.ts | 6 +- .../compiler/tokens/declaration.ts | 393 ++++++ .../tokens/expressions.ts | 114 +- .../{parser => compiler}/tokens/identifier.ts | 6 +- .../{parser => compiler}/tokens/literals.ts | 69 +- .../{parser => compiler}/tokens/operator.ts | 42 +- .../tokens/source_file.ts | 10 +- .../{parser => compiler}/tokens/statement.ts | 233 +++- .../{parser => compiler}/tokens/type.ts | 80 +- .../{compiler => executor}/environment.ts | 62 + .../virtual-machine/executor/index.ts | 46 +- .../instructions/base.ts | 2 +- .../executor/instructions/block.ts | 158 +++ .../instructions/builtin.ts | 7 +- .../instructions/concurrent.ts | 74 +- .../instructions/control.ts | 2 +- .../instructions/funcs.ts | 4 +- .../instructions/index.ts | 0 .../instructions/load.ts | 6 +- .../executor/instructions/memory.ts | 18 + .../instructions/operator.ts | 5 +- .../executor/instructions/store.ts | 53 + .../{compiler => executor}/typing/index.ts | 139 +- .../{compiler => executor}/typing/packages.ts | 31 + .../typing/type_environment.ts | 0 .../virtual-machine/heap/index.ts | 18 +- .../virtual-machine/heap/types/array.ts | 26 +- .../virtual-machine/heap/types/base.ts | 2 +- .../virtual-machine/heap/types/channel.ts | 66 + .../virtual-machine/heap/types/context.ts | 18 +- .../virtual-machine/heap/types/fmt.ts | 14 +- .../virtual-machine/heap/types/func.ts | 32 +- .../virtual-machine/heap/types/mutex.ts | 111 ++ .../virtual-machine/heap/types/primitives.ts | 78 +- .../virtual-machine/heap/types/queue.ts | 28 + .../virtual-machine/heap/types/stack.ts | 26 +- .../virtual-machine/heap/types/struct.ts | 76 + .../virtual-machine/heap/types/waitGroup.ts | 5 +- .../virtual-machine/index.ts | 34 +- .../parser/tokens/declaration.ts | 207 --- .../{executor => runtime}/debugger.ts | 10 +- .../virtual-machine/runtime/index.ts | 17 + .../{executor => runtime}/ops.ts | 0 .../{executor => runtime}/process.ts | 31 +- 106 files changed, 4467 insertions(+), 2421 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 src/go-virtual-machine-main/.vscode/extensions.json delete mode 100644 src/go-virtual-machine-main/.vscode/settings.json delete mode 100644 src/go-virtual-machine-main/frontend/app/App.tsx delete mode 100644 src/go-virtual-machine-main/frontend/app/Router.tsx delete mode 100644 src/go-virtual-machine-main/frontend/app/index.ts delete mode 100644 src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDE.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDEButtons.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/CodeIDE/index.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/ControlBar.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/IO/TextIDE.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/IO/index.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/NavBar.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/Visual/EnvNode.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/Visual/VisualArea.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/Visual/index.tsx delete mode 100644 src/go-virtual-machine-main/frontend/components/Visual/nodes.css delete mode 100644 src/go-virtual-machine-main/frontend/components/index.ts delete mode 100644 src/go-virtual-machine-main/frontend/pages/Main.tsx delete mode 100644 src/go-virtual-machine-main/frontend/stores/executionStore.ts delete mode 100644 src/go-virtual-machine-main/frontend/stores/index.ts delete mode 100644 src/go-virtual-machine-main/frontend/theme/index.ts delete mode 100644 src/go-virtual-machine-main/frontend/theme/theme.ts delete mode 100644 src/go-virtual-machine-main/frontend/types/cytoscape-cola/index.d.ts delete mode 100644 src/go-virtual-machine-main/frontend/types/global.d.ts delete mode 100644 src/go-virtual-machine-main/frontend/utils/error.ts delete mode 100644 src/go-virtual-machine-main/public/cs.png delete mode 100644 src/go-virtual-machine-main/public/gopher.png delete mode 100644 src/go-virtual-machine-main/public/gophers.png delete mode 100644 src/go-virtual-machine-main/public/index.html delete mode 100644 src/go-virtual-machine-main/public/manifest.json delete mode 100644 src/go-virtual-machine-main/public/robots.txt create mode 100644 src/go-virtual-machine-main/tests/mutex.test.ts create mode 100644 src/go-virtual-machine-main/tests/parser.test.ts create mode 100644 src/go-virtual-machine-main/tests/struct.test.ts rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/golang_parser.js (89%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/golang_parser.ts (100%) delete mode 100644 src/go-virtual-machine-main/virtual-machine/compiler/index.ts delete mode 100644 src/go-virtual-machine-main/virtual-machine/compiler/instructions/block.ts delete mode 100644 src/go-virtual-machine-main/virtual-machine/compiler/instructions/store.ts rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/parser.peggy (93%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/parser.ts (100%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens.ts (100%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/base.ts (81%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/block.ts (89%) create mode 100644 src/go-virtual-machine-main/virtual-machine/compiler/tokens/declaration.ts rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/expressions.ts (67%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/identifier.ts (91%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/literals.ts (72%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/operator.ts (60%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/source_file.ts (91%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/statement.ts (64%) rename src/go-virtual-machine-main/virtual-machine/{parser => compiler}/tokens/type.ts (59%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/environment.ts (52%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/base.ts (93%) create mode 100644 src/go-virtual-machine-main/virtual-machine/executor/instructions/block.ts rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/builtin.ts (78%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/concurrent.ts (65%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/control.ts (95%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/funcs.ts (96%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/index.ts (100%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/load.ts (95%) create mode 100644 src/go-virtual-machine-main/virtual-machine/executor/instructions/memory.ts rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/instructions/operator.ts (95%) create mode 100644 src/go-virtual-machine-main/virtual-machine/executor/instructions/store.ts rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/typing/index.ts (63%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/typing/packages.ts (74%) rename src/go-virtual-machine-main/virtual-machine/{compiler => executor}/typing/type_environment.ts (100%) create mode 100644 src/go-virtual-machine-main/virtual-machine/heap/types/mutex.ts create mode 100644 src/go-virtual-machine-main/virtual-machine/heap/types/struct.ts delete mode 100644 src/go-virtual-machine-main/virtual-machine/parser/tokens/declaration.ts rename src/go-virtual-machine-main/virtual-machine/{executor => runtime}/debugger.ts (96%) create mode 100644 src/go-virtual-machine-main/virtual-machine/runtime/index.ts rename src/go-virtual-machine-main/virtual-machine/{executor => runtime}/ops.ts (100%) rename src/go-virtual-machine-main/virtual-machine/{executor => runtime}/process.ts (81%) diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6219d02 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}\\src\\index.tsx", + "outFiles": [ + "${workspaceFolder}/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 6b07362..45a5404 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "eject": "react-scripts eject", "lint-no-fix": "eslint ./ --ignore-path .gitignore && prettier . -c", "lint": "eslint ./ --ignore-path .gitignore --fix && prettier . -c --write", - "generate-parser": "npx peggy --format es -o src/go-virtual-machine-main/virtual-machine/parser/golang_parser.js src/go-virtual-machine-main/virtual-machine/parser/parser.peggy", - "generate-parser-watch": "npx peggy -m -w --format es -o src/go-virtual-machine-main/virtual-machine/parser/golang_parser.js src/go-virtual-machine-main/virtual-machine/parser/parser.peggy" + "generate-parser": "npx peggy --format es -o src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.js src/go-virtual-machine-main/virtual-machine/compiler/parser.peggy", + "generate-parser-watch": "npx peggy -m -w --format es -o src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.js src/go-virtual-machine-main/virtual-machine/compiler/parser.peggy" }, "author": "", "license": "ISC", @@ -35,7 +35,7 @@ "framer-motion": "^10.12.14", "js-cookie": "^3.0.5", "node": "^22.7.0", - "peggy": "^4.0.3", + "peggy": "^4.1.1", "react": "^18.2.0", "react-cytoscapejs": "^2.0.0", "react-data-grid": "^7.0.0-beta.34", diff --git a/src/frontend/components/Visual/EnvNode.tsx b/src/frontend/components/Visual/EnvNode.tsx index eefc9e4..5fcf7f8 100644 --- a/src/frontend/components/Visual/EnvNode.tsx +++ b/src/frontend/components/Visual/EnvNode.tsx @@ -1,7 +1,7 @@ import { Edge, Handle, MarkerType, Node, NodeProps, Position } from 'reactflow' import { Box } from '@chakra-ui/react' -import { EnvironmentInfo } from '../../../virtual-machine/executor/debugger' +import { EnvironmentInfo } from '../../../go-virtual-machine-main/virtual-machine/runtime/debugger' // eslint-disable-next-line @typescript-eslint/no-explicit-any export type Nodes = Node[] diff --git a/src/frontend/components/Visual/VisualArea.tsx b/src/frontend/components/Visual/VisualArea.tsx index a98374a..a76212a 100644 --- a/src/frontend/components/Visual/VisualArea.tsx +++ b/src/frontend/components/Visual/VisualArea.tsx @@ -15,7 +15,7 @@ import { useColorModeValue, } from '@chakra-ui/react' -import { ContextInfo } from '../../../virtual-machine/executor/debugger' +import { ContextInfo } from '../../../go-virtual-machine-main/virtual-machine/runtime/debugger' import { useExecutionStore } from '../../stores' import { addEnvs, EnvNode, Nodes } from './EnvNode' diff --git a/src/frontend/pages/Main.tsx b/src/frontend/pages/Main.tsx index 1623f37..46e06b4 100644 --- a/src/frontend/pages/Main.tsx +++ b/src/frontend/pages/Main.tsx @@ -10,8 +10,8 @@ import { } from '@chakra-ui/react' import Cookies from 'js-cookie' -import { runCode } from '../../virtual-machine' -import { CompileError } from '../../virtual-machine/compiler' +import { runCode } from '../../go-virtual-machine-main/tests/utility' +import { CompileError } from '../../go-virtual-machine-main/virtual-machine/executor/index' import { CodeIDE, CodeIDEButtons, @@ -145,7 +145,7 @@ export const Main = () => { error, output: newOutput, visualData, - } = runCode(code, heapsize, visualMode) + } = runCode(code, heapsize, true, visualMode) if (error) { const errorTitle = { parse: 'Syntax Error', diff --git a/src/frontend/stores/executionStore.ts b/src/frontend/stores/executionStore.ts index 9e51742..6795ce2 100644 --- a/src/frontend/stores/executionStore.ts +++ b/src/frontend/stores/executionStore.ts @@ -1,8 +1,8 @@ import { shallow } from 'zustand/shallow' import { createWithEqualityFn } from 'zustand/traditional' -import { ContextInfo, StateInfo } from '../../virtual-machine/executor/debugger' -import { TokenLocation } from '../../virtual-machine/parser/tokens' +import { ContextInfo, StateInfo } from '../../go-virtual-machine-main/virtual-machine/runtime/debugger' +import { TokenLocation } from '../../go-virtual-machine-main/virtual-machine/compiler/tokens' export interface ExecutionState { currentStep: number diff --git a/src/go-virtual-machine-main/.vscode/extensions.json b/src/go-virtual-machine-main/.vscode/extensions.json deleted file mode 100644 index a17d41f..0000000 --- a/src/go-virtual-machine-main/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["esbenp.prettier-vscode", "peggyjs.peggy-language"] -} diff --git a/src/go-virtual-machine-main/.vscode/settings.json b/src/go-virtual-machine-main/.vscode/settings.json deleted file mode 100644 index ad92582..0000000 --- a/src/go-virtual-machine-main/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": true -} diff --git a/src/go-virtual-machine-main/frontend/app/App.tsx b/src/go-virtual-machine-main/frontend/app/App.tsx deleted file mode 100644 index 2eda9bb..0000000 --- a/src/go-virtual-machine-main/frontend/app/App.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ChakraProvider } from '@chakra-ui/react' - -import { NavBar } from '../components' -import { theme } from '../theme' - -import { Router } from './Router' - -export const App = () => { - return ( - - - - - ) -} diff --git a/src/go-virtual-machine-main/frontend/app/Router.tsx b/src/go-virtual-machine-main/frontend/app/Router.tsx deleted file mode 100644 index ea15044..0000000 --- a/src/go-virtual-machine-main/frontend/app/Router.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Route, Routes } from 'react-router-dom' - -import { Main } from '../pages/Main' - -interface RouteType { - path: string - component: JSX.Element -} - -export const routes: RouteType[] = [ - { - path: '/', - component:
, - }, - { - path: '/go-virtual-machine', - component:
, - }, -] - -export const Router = () => { - return ( - - {routes.map((r) => ( - - ))} - - ) -} diff --git a/src/go-virtual-machine-main/frontend/app/index.ts b/src/go-virtual-machine-main/frontend/app/index.ts deleted file mode 100644 index 5bfcd16..0000000 --- a/src/go-virtual-machine-main/frontend/app/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { App } from './App' diff --git a/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDE.tsx b/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDE.tsx deleted file mode 100644 index bcbc41d..0000000 --- a/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDE.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { useEffect, useRef } from 'react' -import { useColorModeValue } from '@chakra-ui/react' -import { go } from '@codemirror/lang-go' -import { Prec, StateEffect, StateField } from '@codemirror/state' -import { Decoration, keymap } from '@codemirror/view' -import { zebraStripes } from '@uiw/codemirror-extensions-zebra-stripes' -import { githubDark, githubLight } from '@uiw/codemirror-theme-github' -import CodeMirror, { EditorView } from '@uiw/react-codemirror' - -import { useExecutionStore } from '../../stores' - -interface codeIDEProps { - code: string - setCode: (code: string) => void - lineHighlight?: (number | number[])[] - run: () => void - editable: boolean -} - -export const CodeIDE = (props: codeIDEProps) => { - const { location } = useExecutionStore((state) => ({ - location: state.location, - })) - const placeholder = 'Enter your go code here!' - const { code, setCode, lineHighlight } = props - const editorView = useRef(null) - // const [loaded, setLoaded] = useState(false) - - // code mirror effect that you will use to define the effect you want (the decoration) - const highlight_effect = StateEffect.define<{ from: number; to: number }>({ - map: ({ from, to }, change) => ({ - from: change.mapPos(from), - to: change.mapPos(to), - }), - }) - - const highlightField = StateField.define({ - create() { - return Decoration.none - }, - update(highlights, tr) { - highlights = highlights.map(tr.changes) - for (const e of tr.effects) - if (e.is(highlight_effect)) { - highlights = highlights.update({ - add: [highlightMark.range(e.value.from, e.value.to)], - }) - } - return highlights - }, - provide: (f) => EditorView.decorations.from(f), - }) - - const highlightMark = Decoration.mark({ class: 'cm-highlighted' }) - const highlightTheme = EditorView.baseTheme({ - '.cm-highlighted': { - background: useColorModeValue('#F9ffab', '#7c05a2'), - fontWeight: 'bold', - }, - }) - - useEffect(() => { - if (editorView.current && location) { - const effects: StateEffect[] = [ - highlight_effect.of({ - from: location.start.offset, - to: location.end.offset, - }), - ] - effects.push( - StateEffect.appendConfig.of([highlightField, highlightTheme]), - ) - editorView.current.dispatch({ effects }) - } - }, [ - location, - highlightField, - highlightTheme, - highlightMark, - highlight_effect, - ]) - - return ( - { - editorView.current = view - }} - extensions={[ - zebraStripes({ - lineNumber: lineHighlight, - lightColor: '#aca2ff33', - darkColor: '#aca2ff40', - }), - go(), - Prec.high( - keymap.of([ - { - key: 'Shift-Enter', - run: () => { - props.run() - return true - }, - }, - ]), - ), - ]} - onChange={setCode} - theme={useColorModeValue(githubLight, githubDark)} - /> - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDEButtons.tsx b/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDEButtons.tsx deleted file mode 100644 index 2041868..0000000 --- a/src/go-virtual-machine-main/frontend/components/CodeIDE/CodeIDEButtons.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { AiFillCaretRight } from 'react-icons/ai' -import { MdEdit } from 'react-icons/md' -import { - Box, - Button, - Flex, - Icon, - NumberDecrementStepper, - NumberIncrementStepper, - NumberInput, - NumberInputField, - NumberInputStepper, - Spacer, - Tooltip, - useColorModeValue, -} from '@chakra-ui/react' - -interface CodeIDEButtonProps { - isDisabled: boolean - editing: boolean - toggleMode: () => void - heapsize: number - setHeapsize: (x: number) => void -} - -export const CodeIDEButtons = (props: CodeIDEButtonProps) => { - return ( - <> - - Heap Size: - props.setHeapsize(parseInt(value))} - > - - - - - - - - - - - - - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/CodeIDE/index.tsx b/src/go-virtual-machine-main/frontend/components/CodeIDE/index.tsx deleted file mode 100644 index 481f046..0000000 --- a/src/go-virtual-machine-main/frontend/components/CodeIDE/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export * from './CodeIDE' -export * from './CodeIDEButtons' diff --git a/src/go-virtual-machine-main/frontend/components/ControlBar.tsx b/src/go-virtual-machine-main/frontend/components/ControlBar.tsx deleted file mode 100644 index f509117..0000000 --- a/src/go-virtual-machine-main/frontend/components/ControlBar.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { useState } from 'react' -import { FaForward, FaPause, FaPlay } from 'react-icons/fa' -import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons' -import { - Box, - Flex, - IconButton, - Slider, - SliderFilledTrack, - SliderThumb, - SliderTrack, - Spacer, - Stack, - Switch, - Tooltip, - useColorModeValue, -} from '@chakra-ui/react' -import { shallow } from 'zustand/shallow' - -import { useExecutionStore } from '../stores' - -interface ControlBarProps { - playing: boolean - length: number - curSpeed: number - disabled: boolean - wasPlaying: boolean - setSpeed: (speed: number) => void - togglePlaying: () => void - setWasPlaying: (newVal: boolean) => void - moveStep: (forward: boolean) => void - toggleVisual: () => void - visual: boolean -} - -export const ControlBar = (props: ControlBarProps) => { - const { currentStep, setStep } = useExecutionStore( - (state) => ({ - currentStep: state.currentStep, - setStep: state.setStep, - }), - shallow, - ) - const buttonColor = useColorModeValue('#3182ce', '#90cdf4') - const [showTooltip, setShowTooltip] = useState(false) - const [showTooltipMain, setShowTooltipMain] = useState(false) - return ( - <> - - - setShowTooltipMain(true)} - onMouseLeave={() => setShowTooltipMain(false)} - onChangeStart={ - props.playing - ? () => { - props.setWasPlaying(true) - props.togglePlaying() - } - : void 0 - } - onChangeEnd={ - props.wasPlaying - ? () => { - props.setWasPlaying(false) - props.togglePlaying() - } - : void 0 - } - > - - - - - - - - - - - - - - props.setSpeed(Number(v))} - onMouseEnter={() => setShowTooltip(true)} - onMouseLeave={() => setShowTooltip(false)} - isDisabled={props.disabled} - w="120px" - > - - - - - - - - - - - } - onClick={() => props.moveStep(false)} - /> - - ) : ( - - ) - } - onClick={props.togglePlaying} - /> - } - onClick={() => props.moveStep(true)} - /> - - - - Enable Visuals? - - - - - - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/IO/TextIDE.tsx b/src/go-virtual-machine-main/frontend/components/IO/TextIDE.tsx deleted file mode 100644 index d57151a..0000000 --- a/src/go-virtual-machine-main/frontend/components/IO/TextIDE.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useColorModeValue } from '@chakra-ui/react' -import { githubDark, githubLight } from '@uiw/codemirror-theme-github' -import CodeMirror from '@uiw/react-codemirror' - -export interface textIDEProps { - placeholder?: string - setText?: (text: string) => void - text: string - editable: boolean -} - -export const TextIDE = (props: textIDEProps) => { - return ( - - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/IO/index.tsx b/src/go-virtual-machine-main/frontend/components/IO/index.tsx deleted file mode 100644 index 5423c31..0000000 --- a/src/go-virtual-machine-main/frontend/components/IO/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Box } from '@chakra-ui/react' - -import { useExecutionStore } from '../../stores' - -import { TextIDE } from './TextIDE' - -export const IO = () => { - const { output } = useExecutionStore((state) => ({ - output: state.output, - })) - return ( - <> - - - - - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/NavBar.tsx b/src/go-virtual-machine-main/frontend/components/NavBar.tsx deleted file mode 100644 index 015f4bb..0000000 --- a/src/go-virtual-machine-main/frontend/components/NavBar.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { MoonIcon, SunIcon } from '@chakra-ui/icons' -import { - Box, - Button, - Flex, - Heading, - Image, - Stack, - useColorMode, - useColorModeValue, -} from '@chakra-ui/react' - -export const NavBar = () => { - const { colorMode, toggleColorMode } = useColorMode() - return ( - <> - - - - Go Virtual Machine - - - - - - - - - - - - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/Visual/EnvNode.tsx b/src/go-virtual-machine-main/frontend/components/Visual/EnvNode.tsx deleted file mode 100644 index eefc9e4..0000000 --- a/src/go-virtual-machine-main/frontend/components/Visual/EnvNode.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Edge, Handle, MarkerType, Node, NodeProps, Position } from 'reactflow' -import { Box } from '@chakra-ui/react' - -import { EnvironmentInfo } from '../../../virtual-machine/executor/debugger' - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Nodes = Node[] - -export const EnvNode = (props: NodeProps) => { - const { cur, vars, name } = props.data - return ( - <> - - - - {name} - - - {vars.map((x, idx) => ( - - {x.name} = {x.val} - - ))} - - - - - ) -} - -export const addEnvs = ( - env: EnvironmentInfo, - topOffset: number, - leftOffset: number, - nodes: Nodes, - edges: Edge[], -) => { - nodes.push({ - id: 'env ' + env.addr.toString(), - data: { - ...env, - }, - position: { x: leftOffset, y: topOffset }, - type: 'EnvNode', - style: { - width: 200, - height: 40 + env.vars.length * 26, - }, - }) - topOffset += 40 + env.vars.length * 30 + 20 - let sibling = false - for (const child of env.children) { - edges.push({ - id: env.addr.toString() + '->' + child.addr.toString(), - source: 'env ' + env.addr.toString(), - target: 'env ' + child.addr.toString(), - markerEnd: { - type: MarkerType.ArrowClosed, - width: 30, - height: 20, - }, - }) - if (sibling) leftOffset = nodes[nodes.length - 1].position.x + 220 - addEnvs(child, topOffset, leftOffset, nodes, edges) - sibling = true - } -} diff --git a/src/go-virtual-machine-main/frontend/components/Visual/VisualArea.tsx b/src/go-virtual-machine-main/frontend/components/Visual/VisualArea.tsx deleted file mode 100644 index a98374a..0000000 --- a/src/go-virtual-machine-main/frontend/components/Visual/VisualArea.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import 'reactflow/dist/style.css' -import './nodes.css' - -import { useEffect, useMemo, useState } from 'react' -import ReactFlow, { Background, Controls, Edge } from 'reactflow' -import { LockIcon } from '@chakra-ui/icons' -import { - Box, - Flex, - Tab, - TabList, - TabPanel, - TabPanels, - Tabs, - useColorModeValue, -} from '@chakra-ui/react' - -import { ContextInfo } from '../../../virtual-machine/executor/debugger' -import { useExecutionStore } from '../../stores' - -import { addEnvs, EnvNode, Nodes } from './EnvNode' - -// import { useExecutionStore } from '../../stores' - -export const VisualArea = () => { - const { cur_data } = useExecutionStore((state) => ({ - cur_data: state.cur_data, - })) - const nodeTypes = useMemo( - () => ({ - EnvNode: EnvNode, - }), - [], - ) - const genVisual = (info: ContextInfo) => { - const instrNodes = () => { - return info.instrs.map((instr, idx) => { - const bgColor = instr.cur ? '#Caf7cb' : 'white' - return { - id: 'instr ' + instr.idx.toString(), - data: { label: instr.idx.toString() + ': ' + instr.val }, - position: { x: 12.5, y: 30 * (idx + 1) }, - parentId: 'instr', - style: { - width: 200, - height: 30, - padding: '5px', - backgroundColor: bgColor, - }, - } - }) - } - - const osNodes = () => { - const valNodes = info.OS.map((os, idx) => { - return { - id: 'os ' + os.addr.toString(), - data: { label: os.val }, - position: { x: 12.5, y: 30 * (idx + 1) }, - parentId: 'OS', - style: { - width: 200, - height: 30, - padding: '5px', - borderColor: os.modified ? 'red' : 'black', - color: os.modified ? 'red' : 'black', - fontWeight: os.modified ? 'bold' : 'normal', - }, - } - }) - return [ - { - id: 'OS', - data: { label: 'Operand Stack' }, - position: { x: 10, y: 275 }, - className: 'light', - style: { - backgroundColor: '#Cadbf7', - width: 225, - height: 40 + info.OS.length * 30, - padding: '5px', - }, - }, - ...valNodes, - ] - } - - const envNodes: Nodes = [] - const envEdges: Edge[] = [] - if (info.envs.children.length) { - addEnvs(info.envs.children[0], 10, 250, envNodes, envEdges) - } - - const nodes: Nodes = [ - { - id: 'instr', - data: { label: 'Instructions' }, - position: { x: 10, y: 10 }, - className: 'light', - style: { - backgroundColor: '#Cadbf7', - width: 225, - height: 250, - padding: '5px', - }, - }, - ...(cur_data.length ? instrNodes() : []), - ...(cur_data.length ? osNodes() : []), - ...envNodes, - ] - const edges = [...envEdges] - return { nodes, edges } - } - const visualBgColor = useColorModeValue('white', 'gray.800') - const [tabIndex, setTabIndex] = useState(0) - useEffect(() => { - if (tabIndex >= cur_data.length) setTabIndex(0) - }, [tabIndex, cur_data]) - return ( - <> - - - setTabIndex(index)} - h="100%" - > - - {cur_data.map((ctx, idx) => { - return ( - - {ctx.blocked && } Thread {ctx.id} - - ) - })} - - - {cur_data.map((ctx, idx) => { - const { nodes, edges } = genVisual(ctx) - return ( - -
- - - - -
-
- ) - })} -
-
-
-
- - ) -} diff --git a/src/go-virtual-machine-main/frontend/components/Visual/index.tsx b/src/go-virtual-machine-main/frontend/components/Visual/index.tsx deleted file mode 100644 index 52cbcc7..0000000 --- a/src/go-virtual-machine-main/frontend/components/Visual/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './VisualArea' diff --git a/src/go-virtual-machine-main/frontend/components/Visual/nodes.css b/src/go-virtual-machine-main/frontend/components/Visual/nodes.css deleted file mode 100644 index 11c0bf4..0000000 --- a/src/go-virtual-machine-main/frontend/components/Visual/nodes.css +++ /dev/null @@ -1,3 +0,0 @@ -.react-flow__handle { - opacity: 0; -} diff --git a/src/go-virtual-machine-main/frontend/components/index.ts b/src/go-virtual-machine-main/frontend/components/index.ts deleted file mode 100644 index 3b1eeae..0000000 --- a/src/go-virtual-machine-main/frontend/components/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './CodeIDE' -export * from './ControlBar' -export * from './IO' -export * from './NavBar' -export * from './Visual' diff --git a/src/go-virtual-machine-main/frontend/pages/Main.tsx b/src/go-virtual-machine-main/frontend/pages/Main.tsx deleted file mode 100644 index 1623f37..0000000 --- a/src/go-virtual-machine-main/frontend/pages/Main.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import { createContext, useEffect, useState } from 'react' -import { - Box, - Center, - Flex, - Image, - keyframes, - useInterval, - useToast, -} from '@chakra-ui/react' -import Cookies from 'js-cookie' - -import { runCode } from '../../virtual-machine' -import { CompileError } from '../../virtual-machine/compiler' -import { - CodeIDE, - CodeIDEButtons, - ControlBar, - IO, - VisualArea, -} from '../components' -import { useExecutionStore } from '../stores' - -export const LoaderContext = createContext< - React.Dispatch> | undefined ->(undefined) - -const COOKIE_NAME = 'code_value' -const VISUAL_MODE = 'visual_mode' - -export const Main = () => { - const { setVisualData, currentStep, setStep, data, setOutput, setLocation } = - useExecutionStore((state) => ({ - data: state.data, - setVisualData: state.setVisualData, - currentStep: state.currentStep, - setStep: state.setStep, - setOutput: state.setOutput, - setLocation: state.setLocation, - })) - const [editing, setEditing] = useState(true) - const [isPlaying, setPlaying] = useState(false) - const [wasPlaying, setWasPlaying] = useState(false) - const [speed, setSpeed] = useState(1) - const [loading, setLoading] = useState(false) - const [code, setCode] = useState('') - const [heapsize, setHeapsize] = useState(2048) - const [visualMode, setVisualMode] = useState(false) - - useEffect(() => { - // Get the value from the cookie - const oldCode = Cookies.get(COOKIE_NAME) - const visualMode = Cookies.get(VISUAL_MODE) - // Update state if the cookie exists - if (oldCode) { - try { - setCode(atob(oldCode)) - } catch (_err) { - Cookies.remove(COOKIE_NAME) - } - } - if (visualMode === 'true') { - setVisualMode(true) - } - }, []) - - const modifyCode = (code: string) => { - Cookies.set(COOKIE_NAME, btoa(code)) - setCode(code) - resetErrors() - resetMarking() - } - - const toggleVisualMode = () => { - Cookies.set(VISUAL_MODE, (!visualMode).toString()) - setVisualMode(!visualMode) - } - - const toast = useToast() - const makeToast = ( - msg: string | undefined, - title = 'An Error Has Occured!', - ) => { - toast({ - title, - description: msg, - status: 'error', - duration: 2000, - isClosable: true, - containerStyle: { - whiteSpace: 'pre-line', - }, - }) - } - - /** - * Interval hook to increment the step counter while the execution is playing - */ - useInterval( - () => { - // sanity check - if (currentStep >= 0 && currentStep + 1 < data.length) { - setStep(currentStep + 1) - } - if (currentStep >= data.length - 1) { - // End of execution - setPlaying(false) - } - }, - isPlaying ? Math.ceil(1000 / speed) : null, - ) - - const moveStep = (forward: boolean) => { - const newStep = Math.min( - data.length, - Math.max(0, (forward ? 1 : -1) * speed + currentStep), - ) - setStep(newStep) - if (newStep >= data.length) { - setPlaying(false) - } - } - - const [lineHighlight, setLineHighlight] = useState<(number | number[])[]>([0]) - - const resetErrors = () => { - setLineHighlight([0]) - } - - const resetMarking = () => { - setLocation(null) - } - const toggleEditing = async () => { - if (editing) { - // Start playing - setLoading(true) - if (code === '') { - setLoading(false) - makeToast('Code cannot be empty!') - return - } - // Retrieve instructions from endpoint - setOutput('Compiling and Running your code...') - const { - error, - output: newOutput, - visualData, - } = runCode(code, heapsize, visualMode) - if (error) { - const errorTitle = { - parse: 'Syntax Error', - compile: 'Compile Error', - runtime: 'Runtime Error', - }[error.type] - setLoading(false) - makeToast(error.message, errorTitle) - - if (error.type === 'compile') { - // Highlight compile error in source code. - const details = error.details as CompileError - const startLine = details.sourceLocation.start.line - let endLine = details.sourceLocation.end.line - if (details.sourceLocation.end.column === 1) { - // When parsing, the token's end location may spill into the next line. - // If so, then we should ignore the last line. - endLine-- - } - setLineHighlight([[startLine, endLine]]) - } - } else { - resetErrors() - } - console.log(error, !error, error?.type === 'runtime') - if (!error || error.type === 'runtime') { - setEditing(!editing) - - // Set instructions and update components to start playing mode - setVisualData(visualData) - if (visualData.length === 0) setOutput(newOutput || '') - setPlaying(true) - setWasPlaying(false) - setTimeout(function () { - setLoading(false) - }, 500) - } - } else { - // Stop playing - setPlaying(false) - setEditing(!editing) - } - } - - const spin = keyframes` - from {transform: rotate(0deg);} - to {transform: rotate(360deg)} - ` - - return ( - - {loading ? ( -
- -
- ) : null} - - - - - - - - - - - - - - { - if (isPlaying || currentStep < data.length) - setPlaying(!isPlaying) - }} - disabled={data.length === 0 || editing} - wasPlaying={wasPlaying} - setWasPlaying={setWasPlaying} - moveStep={moveStep} - toggleVisual={toggleVisualMode} - visual={visualMode} - /> - - - - - -
- ) -} diff --git a/src/go-virtual-machine-main/frontend/stores/executionStore.ts b/src/go-virtual-machine-main/frontend/stores/executionStore.ts deleted file mode 100644 index 9e51742..0000000 --- a/src/go-virtual-machine-main/frontend/stores/executionStore.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { shallow } from 'zustand/shallow' -import { createWithEqualityFn } from 'zustand/traditional' - -import { ContextInfo, StateInfo } from '../../virtual-machine/executor/debugger' -import { TokenLocation } from '../../virtual-machine/parser/tokens' - -export interface ExecutionState { - currentStep: number - setStep: (step: number) => void - data: StateInfo[] - setVisualData: (data: StateInfo[]) => void - cur_data: ContextInfo[] - output: string - setOutput: (output: string) => void - setLocation: (location: TokenLocation | null) => void - location: TokenLocation | null -} - -const defaultValues = { - currentStep: 0, - data: [], - cur_data: [], - output: '', - location: null, -} - -/** - * Factory function for execution store - * with option to seed inital values (For automated tests) - * @param initalValues Initial Values (optional) - * @returns - */ -export const createExecutionStore = (initialState: Partial) => { - return createWithEqualityFn( - (set, get) => ({ - ...defaultValues, - /** - * Change the current execution step to given value. - * Note this operation updates all related variables like table data - * @param step - */ - setStep: (step: number) => { - if (step < get().data.length) { - set({ - currentStep: step, - cur_data: get().data[step].contexts, - output: get().data[step].output, - location: get().data[step].location, - }) - } - }, - /** - * Resets the execution from the start with new instructions. - * @param instructions New instructions - */ - setVisualData: (data: StateInfo[]) => { - set({ - currentStep: 0, - data, - }) - }, - setOutput: (output: string) => { - set({ output }) - }, - setLocation: (location: TokenLocation | null) => { - set({ location }) - }, - ...initialState, - }), - shallow, - ) -} - -export const useExecutionStore = createExecutionStore({}) diff --git a/src/go-virtual-machine-main/frontend/stores/index.ts b/src/go-virtual-machine-main/frontend/stores/index.ts deleted file mode 100644 index 6233b37..0000000 --- a/src/go-virtual-machine-main/frontend/stores/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './executionStore' diff --git a/src/go-virtual-machine-main/frontend/theme/index.ts b/src/go-virtual-machine-main/frontend/theme/index.ts deleted file mode 100644 index fc6c2f6..0000000 --- a/src/go-virtual-machine-main/frontend/theme/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './theme' diff --git a/src/go-virtual-machine-main/frontend/theme/theme.ts b/src/go-virtual-machine-main/frontend/theme/theme.ts deleted file mode 100644 index fb242ec..0000000 --- a/src/go-virtual-machine-main/frontend/theme/theme.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { extendTheme } from '@chakra-ui/react' - -export const theme = extendTheme({ - styles: { - global: { - '#root': { - display: 'flex', - flexDirection: 'column', - minHeight: '100vh', - }, - }, - }, - fonts: { - heading: `'Open Sans', sans-serif`, - body: `'Raleway', sans-serif`, - }, -}) diff --git a/src/go-virtual-machine-main/frontend/types/cytoscape-cola/index.d.ts b/src/go-virtual-machine-main/frontend/types/cytoscape-cola/index.d.ts deleted file mode 100644 index 908139b..0000000 --- a/src/go-virtual-machine-main/frontend/types/cytoscape-cola/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'cytoscape-cola' diff --git a/src/go-virtual-machine-main/frontend/types/global.d.ts b/src/go-virtual-machine-main/frontend/types/global.d.ts deleted file mode 100644 index 6c344ed..0000000 --- a/src/go-virtual-machine-main/frontend/types/global.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.module.css' diff --git a/src/go-virtual-machine-main/frontend/utils/error.ts b/src/go-virtual-machine-main/frontend/utils/error.ts deleted file mode 100644 index 4f134ac..0000000 --- a/src/go-virtual-machine-main/frontend/utils/error.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Extract printable string from JS Error - * @param error Thrown Error - * @returns Error message if exist else stringify error - */ -export function getErrorMessage(error: unknown) { - console.log(error) - if (error instanceof Error) return error.message - return String(error) -} diff --git a/src/go-virtual-machine-main/index.tsx b/src/go-virtual-machine-main/index.tsx index c038e52..88370cd 100644 --- a/src/go-virtual-machine-main/index.tsx +++ b/src/go-virtual-machine-main/index.tsx @@ -2,7 +2,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' import { BrowserRouter } from 'react-router-dom' -import { App } from './frontend/app' +import { App } from '../frontend/app' const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement) root.render( diff --git a/src/go-virtual-machine-main/public/cs.png b/src/go-virtual-machine-main/public/cs.png deleted file mode 100644 index dbabf5c3d70fac8ccbf4ff41d8312da220cb61bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2210 zcmai$YdjN-0>(uYH6kkwBQckbTN{()wz-=-MK8IR* zay#y8_=vg_DSqBTF5BDNJJ{FPXKrqupPvr~gE<^dU0vPFmoN48^%oWv3JVKaEEX1v z9T*ruqtU;9{Su4COG`^|IJ~;L+Sk{2czAgK{{7?Q<1H;M_V)H{Hv8<^v+3#S=gyro zF)?v>cLxH2<>lpBSy|4`&M`4DH();-Yf!b_D{sp=lTq8yYg#h=vN4ZIgqWph~xK^5i?3q$KjH_Kk^=b}wt3 z+vvrl#9O&$0}CwP1S9nKq*f-nOSslL5Y|$y&H9hk2Lyg>w6!gBxbwy+9<_QKV0{#A zJ$A3QQ<`;{R0E*D3ZH-Sv=G41rqtZ6mlz+1Y9cp2T}x~AjGIat&DLU);%a{z$2+wO z_{b76?+bHcmZQ|DO2t))41St0mfjdCGY4%BEVY37SSO%OzF^x5 z5P>f!1t>6;7|C&|lUGCrsy4jm-bU$BiJwj-^h4ADo#VnH6og6)Ssh0iQ9;=mIB!Yz zJ;u?l_Fc5IuwH9^Jh?E0hOz(=5w>$I4_8E@4mFV>m}?u@!BkUgF}e~}ulp5kq?OR* zUz!H%trJ`-7C?5(^{=7K`fQvBXI1D(7u^B+G7l;>!7!z(cCZhcOR_mCj)d2~_ zI1=I*Mk0v#ftH;XsHMYp{XiGkQDxFQkYLnxyD+^Hh$Gmv%NJuQ z^-?^~>a1uKv-RZ2B@Jdu!W;^A-vpfunvPe$E0JdW*n|0ge%aTIF9*X#NKmlwRt zoU7r?WQ#L|OUaUbgR9$duqp#NiUB;4z`?MVR}@Lv_wr6&iju~JTQcaHo7hRx>}vcQ z4bvo+M@CQEvgH+BR~YQzU=eb2$?97R*ZBKZbeEenS=X#Y1popx0q&YSg&2blH($?} zAP~tR6=65uUG6>~GjvNONrCi*L;B3t2au+~Kl!bE_hT`QyB7JvQXGM(N`Ae_{Vr|E6q=_;&J0q{&%h_$Qf;h)DY;5gHr zcky^<`wnFoH*>uNj=x5K)mH6B>3hHAu2KIQ8&I~`x^3msK_|_i@yu`9QAk9xYJ^)| zm=#)QYcpf=BZT<~zGVK=!nxB;=OMmU;~2;@vgkR$W@*!FzG&twUv}$!LSCRH<7i+I z@XPIuRb=a@=RK-&%7&tYYCdcg=?^gxz_ZRgf5zsooN)QyB2Tje>=J^VO=Oll$|}PC z>a^dkh&^cLqC?y&cq;eI&r_F%zAK9`R(Vq5-{V$3aUEb$IRLSK8&U57>z3 z`_C`pm5APd)RrZOd-HluaKD{)C!?mXSUg54=PXP~yD{leYTPp&Jw4Qh<+yJFbmG&*>)bQYs!Q#xzT2A#9A5#KXnukUu zN1sa!8WP7Irj*y11&)OhCggZirRE&}=5gV)G`)JTyWgHRvYwQZR=I#l){)9gK)6gR zfAtQ+-9~!tNU=Qj822(=$|l`g7AKO8w=0%+T(<8qzhzfhODGh5-#P;+JvLm|v zGF|^?#0XfwR?CT*F+TUAYhAtXKg|R-WGa*?&A?E*Y0=G3g zn42Kbe27ZR2+b3i@?(x^o(5tmd{Sg$Ugr! z#kfX=Kq0e)big#XDr(E6-bC3mujdG1x^T_bz9Tg}7$qpyI1RLJr2RJXrI1xut2h|m en-oXK%{@I95B()rSjo=QknwQwLAE+aX8!}uPBX;- diff --git a/src/go-virtual-machine-main/public/gopher.png b/src/go-virtual-machine-main/public/gopher.png deleted file mode 100644 index 9b9e43ea7e927e794a1d0c4700946c002558cac6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137116 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

?5hy~jA-ocO_Z&+=$Q0$Q)a;` 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 ZoSvKmmOt)n*alo2U2OxcN)7vn{{xaN0!#n^ diff --git a/src/go-virtual-machine-main/public/index.html b/src/go-virtual-machine-main/public/index.html deleted file mode 100644 index 4aafce4..0000000 --- a/src/go-virtual-machine-main/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - Go-VM - - - -

- - - diff --git a/src/go-virtual-machine-main/public/manifest.json b/src/go-virtual-machine-main/public/manifest.json deleted file mode 100644 index 6414a4e..0000000 --- a/src/go-virtual-machine-main/public/manifest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "short_name": "Go VM", - "name": "Go Virtual Machine", - "icons": [ - { - "src": "/cs.png", - "sizes": "32x32", - "type": "image/png", - "density": "1.0" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/src/go-virtual-machine-main/public/robots.txt b/src/go-virtual-machine-main/public/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/src/go-virtual-machine-main/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/src/go-virtual-machine-main/tests/array.test.ts b/src/go-virtual-machine-main/tests/array.test.ts index 907a6e0..b0dffe1 100644 --- a/src/go-virtual-machine-main/tests/array.test.ts +++ b/src/go-virtual-machine-main/tests/array.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Array Type Checking', () => { test('Array literal with more elements than in the type should fail.', () => { @@ -11,18 +11,41 @@ describe('Array Type Checking', () => { ) }) + test('Commas as part of string literals should pass correctly', () => { + expect( + mainRunner(`var a [3]string = [3]string{"1", "2, 3", "4"} + fmt.Println(a)`).output, + ).toEqual( + '[1 2, 3 4]\n', + ) + }) + test('Array literal with less elements than in the type should still pass.', () => { const code = - `var a [3]int = [3]int{1} + `var a [3]int = [3]int{1} fmt.Println(a)` expect(mainRunner(code).output).toEqual('[1 0 0]\n') }) + test('Array boolean literal with less elements than in the type should still pass.', () => { + const code = + `var a [3]bool = [3]bool{true} + fmt.Println(a)` + expect(mainRunner(code).output).toEqual('[true false false]\n') + }) + + test('Array string literal with less elements than in the type should still pass.', () => { + const code = + `var a [3]string = [3]string{"Hi", "there"} + fmt.Println(a)` + expect(mainRunner(code).output).toEqual('[Hi there ]\n') + }) + test('Array literal should ignore newline between elements being declared.', () => { // note: does not ignore newline between elements and comma/close semi-colon, // it would result in compilation error even in the actual language const code = - ` var a [3]int = [3]int{ + ` var a [3]int = [3]int{ 1, 2, 3} @@ -69,11 +92,158 @@ describe('Array Execution', () => { ).toEqual('Execution Error: Index out of range [3] with length 3') }) - test('Nested arrays work.', () => { + test('2D arrays work with partial initialisation.', () => { + expect( + mainRunner( + `a := [3][3]int{{1, 2}, {4, 5, 6}, {7}}; + fmt.Println(a) + `, + ).output, + ).toEqual('[[1 2 0] [4 5 6] [7 0 0]]\n') + }) + + test('2D arrays work.', () => { + expect( + mainRunner( + `a := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + fmt.Println(a[1][2]) + fmt.Println(a[0][1]) + fmt.Println(a[2][1]) + fmt.Println(a[1][1]) + fmt.Println(a[0][2]) + fmt.Println(a[0][0]) + fmt.Println(a[2][2]) + fmt.Println(a[1][0]) + fmt.Println(a[2][0]) + fmt.Println(a) + `, + ).output, + ).toEqual('6\n2\n8\n5\n3\n1\n9\n4\n7\n[[1 2 3] [4 5 6] [7 8 9]]\n') + }) + + test('3D arrays work.', () => { + expect( + mainRunner( + `arr2D := [2][3][4]int{{{1, 2, 3, 11}, {4, 5, 6, 22}, {7, 8, 9, 33}}, {{10, 20, 30, 44}, {40, 50, 60, 55}, {70, 80, 90, 66}}} + fmt.Println(arr2D) + `, + ).output, + ).toEqual('[[[1 2 3 11] [4 5 6 22] [7 8 9 33]] [[10 20 30 44] [40 50 60 55] [70 80 90 66]]]\n') + }) + + test('2D arrays work with reassignments.', () => { expect( mainRunner( - 'a := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; fmt.Println(a[1][2])', + `a := [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + a[0][0] = 5 + a[0][1] = 6 + a[0][2] = 7 + a[1][0] = 8 + a[1][1] = 9 + a[1][2] = 10 + a[2][0] = 11 + a[2][1] = 12 + a[2][2] = 13 + fmt.Println(a[1][2]) + fmt.Println(a[0][1]) + fmt.Println(a[2][1]) + fmt.Println(a[1][1]) + fmt.Println(a[0][2]) + fmt.Println(a[0][0]) + fmt.Println(a[2][2]) + fmt.Println(a[1][0]) + fmt.Println(a[2][0]) + `, ).output, - ).toEqual('6\n') + ).toEqual('10\n6\n12\n9\n7\n5\n13\n8\n11\n') + }) + + test('Single element assignment should fail when using multiple return values from a single function', () => { + const code = ` + package main + import "fmt" + + func help2(a int) (int, int) { + return a * 2, a * 3 + } + + func main() { + a := [2]int{help2(24)} + fmt.Println(a) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Array assignment should fail when using multiple return values from a single function', () => { + const code = ` + package main + import "fmt" + + func help2(a int) (int, int) { + return a * 2, a * 3 + } + + func main() { + a := [2]int{0, 0} + a = help2(4) + fmt.Println(a) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Array multiple elements assignment should work when using multiple return values from a single function', () => { + const code = ` + package main + import "fmt" + + func help2(a int) (int, int) { + return a * 2, a * 3 + } + + func main() { + a := [4]int{0, 0, 0, 0} + a[0], a[2] = help2(4) + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[8 0 12 0]\n") + }) + + test('Array multiple elements assignment should work when using multiple return values from a single function', () => { + const code = ` + package main + import "fmt" + + func help2(a int) (int, int, int, int) { + return a * 2, a * 3, a * 6, a * 10 + } + + func main() { + a := [4]int{0, 0, 0, 0} + a[0], a[2], a[3], a[1] = help2(4) + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[8 40 12 24]\n") + }) + + test('Array multiple elements assignment should work with expression indices when using multiple return values from a single function', () => { + const code = ` + package main + import "fmt" + + func help2(a int) (int, int, int, int) { + return a * 2, a * 3, a * 6, a * 10 + } + + func main() { + a := [4]int{0, 0, 0, 0} + a[0 + 3], a[2 - 1], a[3 * 0], a[6 / 3] = help2(4 + 7) + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[66 33 110 22]\n") }) }) diff --git a/src/go-virtual-machine-main/tests/builtin.test.ts b/src/go-virtual-machine-main/tests/builtin.test.ts index 8bd8e2e..1b93854 100644 --- a/src/go-virtual-machine-main/tests/builtin.test.ts +++ b/src/go-virtual-machine-main/tests/builtin.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Builtins Type Checking', () => { test('Assignment of make with incompatible type should fail', () => { @@ -8,4 +8,13 @@ describe('Builtins Type Checking', () => { mainRunner('var a chan int = make(chan string)').error?.message, ).toEqual('Cannot use chan string as chan int64 in variable declaration') }) -}) + + test('Reassignment to constants should fail', () => { + expect( + mainRunner(` + const a = 5 + a = 6 + `).error?.message, + ).toEqual('cannot assign to a (neither addressable nor a map index expression)') + }) +}) \ No newline at end of file diff --git a/src/go-virtual-machine-main/tests/channel.test.ts b/src/go-virtual-machine-main/tests/channel.test.ts index 1e65508..30215a9 100644 --- a/src/go-virtual-machine-main/tests/channel.test.ts +++ b/src/go-virtual-machine-main/tests/channel.test.ts @@ -36,6 +36,17 @@ describe('Channel Tests', () => { ).toEqual('9\n') }) + test('Input type mismatch should throw error', () => { + expect( + mainRunner(` + c1 := make(chan int) + go func() { + c1<- "Hello" + }() + fmt.Println(4 + <- c1)`).error?.type, + ).toEqual('compile') + }) + test('Channels Select Case Test', () => { const strs = mainRunner(` c1 := make(chan int) diff --git a/src/go-virtual-machine-main/tests/comment.test.ts b/src/go-virtual-machine-main/tests/comment.test.ts index fa9b3b3..9eecc29 100644 --- a/src/go-virtual-machine-main/tests/comment.test.ts +++ b/src/go-virtual-machine-main/tests/comment.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { runCode } from '../virtual-machine' +import { codeRunner } from './utility' describe('Comments Tests', () => { test('Comments are correctly ignored', () => { @@ -22,6 +22,6 @@ describe('Comments Tests', () => { fmt.Println(/* comment in middle of code */a) } ` - expect(runCode(code, 2048).output).toEqual('3\n') + expect(codeRunner(code).output).toEqual('3\n') }) }) diff --git a/src/go-virtual-machine-main/tests/concurrency.test.ts b/src/go-virtual-machine-main/tests/concurrency.test.ts index be5fef6..907d8bc 100644 --- a/src/go-virtual-machine-main/tests/concurrency.test.ts +++ b/src/go-virtual-machine-main/tests/concurrency.test.ts @@ -1,9 +1,27 @@ import { describe, expect, test } from 'vitest' -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Concurrency Check', () => { - test('Basic Check', () => { + test('Basic Check for small loops', () => { + expect( + codeRunner(` + package main + import "fmt" + func add(a int){ + fmt.Println(a); + } + + func main() { + for i := 0; i < 10; i++ { + go add(i); + } + fmt.Println("Done"); + } + `).output, + ).toEqual('0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nDone\n') + }) + test('Basic Check for large loops', () => { expect( mainRunner(` a := 0 @@ -36,4 +54,46 @@ describe('Concurrency Check', () => { ), ).toBeLessThan(500) }) -}) + + test(`Arguments supplied to go statements are evaluated at that line + with calling an anonymous function`, () => { + const code = ` + package main + import "fmt" + import "sync" + + func main() { + a := 3 + var wg sync.WaitGroup + wg.Add(1) + go func(b int) { + fmt.Println(b) + wg.Done() + }(a) + a = a + 345 + fmt.Println("hello") + wg.Wait() + } + ` + expect(codeRunner(code).output).toEqual('3\nhello\n') + }) + + test(`Arguments supplied to go statements are evaluated at that line + with calling a pre-declared function`, () => { + const code = ` + package main + import "fmt" + import "sync" + + func main() { + a := 3 + go fmt.Println(a) + a = a + 345 + go fmt.Println(a) + a = a + 1000 + fmt.Println("hello") + } + ` + expect(codeRunner(code).output).toEqual('3\n348\nhello\n') + }) +}) \ No newline at end of file diff --git a/src/go-virtual-machine-main/tests/declaration.test.ts b/src/go-virtual-machine-main/tests/declaration.test.ts index 7945512..efc366a 100644 --- a/src/go-virtual-machine-main/tests/declaration.test.ts +++ b/src/go-virtual-machine-main/tests/declaration.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Variable Declaration Tests', () => { test('Const Variables', () => { @@ -76,4 +76,627 @@ describe('Variable Declaration Tests', () => { ` expect(mainRunner(code).output).toEqual('') }) + + test('Declaring variables with same name in same scope should throw compilation error', () => { + const code = ` + x, x := 3, 6 + ` + expect(mainRunner(code).error?.type).toEqual("compile") + }) + + test('Declaring variables with same name in different scopes should pass', () => { + const code = ` + x := 2 + { + x := 3 + fmt.Println(x) + } + fmt.Println(x) + ` + expect(mainRunner(code).output).toEqual("3\n2\n") + }) + + test('Reassignment to a different type should fail', () => { + const code = ` + x := 2 + x = "Hi" + ` + expect(mainRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should work for multiple layers', () => { + const code = ` + type Age int + type B Age + var x B = 3 + fmt.Println(x) + ` + expect(mainRunner(code).output).toEqual('3\n') + }) + + test('Type declaration should work', () => { + const code = ` + type Age int + var x Age = 3 + fmt.Println(x) + ` + expect(mainRunner(code).output).toEqual('3\n') + }) + + test('Type declaration should not interfere with primitive declarations', () => { + const code = ` + type Age int + type B Age + var x int = 3 + fmt.Println(x) + ` + expect(mainRunner(code).output).toEqual('3\n') + }) + + test('Type declaration should throw error if not found', () => { + const code = ` + type Age int + type B Ag + ` + expect(mainRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should throw error if types do not match in binop', () => { + const code = ` + type Age int + type Num Age + var x Num = 3 + var y int = 2 + x = x + y + ` + expect(mainRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should throw error if types do not match in assignment', () => { + const code = ` + type Age int + type Num Age + var x Num = 3 + var y int = 2 + x = y + ` + expect(mainRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration based on int should still work correctly when applying binops', () => { + const code = ` + type Age int + type Num Age + var x Num = 6 + fmt.Println(x + 2) + fmt.Println(x / 2) + fmt.Println(x * 2) + fmt.Println(x - 2) + fmt.Println((x + 2) * 2) + fmt.Println((x - 2) / 2) + fmt.Println(x * x) + fmt.Println(x / x) + ` + expect(mainRunner(code).output).toEqual("8\n3\n12\n4\n16\n2\n36\n1\n") + }) + + test('Type declaration based on int should still work correctly when applying arithmetic assignments', () => { + const code = ` + type Age int + type Num Age + var x Num = 6 + x += 3 + fmt.Println(x) + x -= 1 + fmt.Println(x) + x *= 3 + fmt.Println(x) + x /= 4 + fmt.Println(x) + x += 2 * x + fmt.Println(x) + x *= x - 1 + fmt.Println(x) + x /= x / 2 + fmt.Println(x) + x -= x + 2 + fmt.Println(x) + ` + expect(mainRunner(code).output).toEqual("9\n8\n24\n6\n18\n306\n2\n-2\n") + }) + + test('Type declaration based on string should still work correctly when applying +', () => { + const code = ` + type text string + var x text = "Hello" + fmt.Println(x + "4") + ` + expect(mainRunner(code).output).toEqual("Hello4\n") + }) + + test('Type declaration based on string should still work correctly when uninitialised', () => { + const code = ` + type text string + var x text + fmt.Println(x + "4") + ` + expect(mainRunner(code).output).toEqual("4\n") + }) + + test('Type declaration based on int should still work correctly when uninitialised', () => { + const code = ` + type Num int + var x Num + fmt.Println(x + 45) + ` + expect(mainRunner(code).output).toEqual("45\n") + }) + + test('Type declaration based on float should still work correctly when uninitialised', () => { + const code = ` + type Num float64 + var x Num + fmt.Println(x + 49.25) + ` + expect(mainRunner(code).output).toEqual("49.25\n") + }) + + test('+ should work on 2 variables with string as underlying type', () => { + const code = ` + type text string + var x text = "Hello" + var y text = " there" + fmt.Println(x + y) + ` + expect(mainRunner(code).output).toEqual("Hello there\n") + }) + + test('+ should work on 2 variables with int as underlying type', () => { + const code = ` + type Age int + type Num Age + var x Num = 3 + var y Num = 2 + fmt.Println(x + y) + ` + expect(mainRunner(code).output).toEqual("5\n") + }) + + test('+ should work on 2 variables with float as underlying type', () => { + const code = ` + type Age float64 + type Num Age + var x Num = 3.5 + var y Num = 2.25 + fmt.Println(x + y) + ` + expect(mainRunner(code).output).toEqual("5.75\n") + }) + + test('+ should work on a variable with float as underlying type and int literal', () => { + const code = ` + type Age float64 + type Num Age + var x Num = 3.25 + fmt.Println(x + 33) + ` + expect(mainRunner(code).output).toEqual("36.25\n") + }) + + test('Type declaration works on function arguments with typed variable', () => { + const code = ` + package main + import "fmt" + + type A int + func help(a A) { + fmt.Println(a) + } + + func main() { + var aa A = 38 + help(aa) + } + ` + expect(codeRunner(code).output).toEqual("38\n") + }) + + test('Type declaration works on function arguments with literal', () => { + const code = ` + package main + import "fmt" + + type A int + func help(a A) { + fmt.Println(a) + } + + func main() { + help(47) + } + ` + expect(codeRunner(code).output).toEqual("47\n") + }) + + test('Type declaration of multiple layers works on function arguments with literal', () => { + const code = ` + package main + import "fmt" + + type A int + type B A + func help(a B) { + fmt.Println(a) + } + + func main() { + help(474) + } + ` + expect(codeRunner(code).output).toEqual("474\n") + }) + + test('Type declaration fails if function argument types do not match (argument = declared, supplied = underlying)', () => { + const code = ` + package main + import "fmt" + + type A int + func help(a A) { + fmt.Println(a) + } + + func main() { + var aa int = 0 + help(aa) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration fails if function argument types do not match (argument = underlying, supplied = declared)', () => { + const code = ` + package main + import "fmt" + + type A int + func help(a int) { + fmt.Println(a) + } + + func main() { + var aa A = 0 + help(aa) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should work on functions with literal as return values used for another function)', () => { + const code = ` + package main + import "fmt" + + type A int + func help(c A) { + fmt.Println(c) + } + + func help2(a A) A { + return 30 + } + + func main() { + help(help2(6)) + } + ` + expect(codeRunner(code).output).toEqual("30\n") + }) + + test('Type declaration should work on functions with matching type return values used for another function)', () => { + const code = ` + package main + import "fmt" + + type A int + func help(c A) { + fmt.Println(c) + } + + func help2(a A) A { + return a * 2 + } + + func main() { + help(help2(6)) + } + ` + expect(codeRunner(code).output).toEqual("12\n") + }) + + test('Type declaration should fail on functions with not matching type return values used for another function)', () => { + const code = ` + package main + import "fmt" + + type A int + type B int + func help(c B) { + fmt.Println(c) + } + + func help2(a A) A { + return 2 + } + + func main() { + help(help2(6)) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should work on arrays', () => { + const code = ` + package main + import "fmt" + + func main() { + type B int + a := []B{12, 21} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[12 21]\n") + }) + + test('Type declaration should work on arrays (double layer)', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + type B A + a := []B{12, 21} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[12 21]\n") + }) + + test('Type declaration should work on 1D arrays', () => { + const code = ` + package main + import "fmt" + + func main() { + type B int + a := []B{12, 21} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[12 21]\n") + }) + + test('Type declaration should work on 2D arrays', () => { + const code = ` + package main + import "fmt" + + func main() { + type B int + a := [][]B{{12, 18}, {21, 93}} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[[12 18] [21 93]]\n") + }) + + test('Type declaration should work on arrays (double layer)', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + type B A + a := []B{12, 21} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[12 21]\n") + }) + + test('Type declaration should work on array elements', () => { + const code = ` + package main + import "fmt" + + func main() { + type B int + a := []B{12, 21} + fmt.Println(a[0] + a[1]) + } + ` + expect(codeRunner(code).output).toEqual("33\n") + }) + + test('Type declaration should work on array elements (double layer)', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + type B A + a := []B{12, 21} + fmt.Println(a[0] + a[1]) + } + ` + expect(codeRunner(code).output).toEqual("33\n") + }) + + test('Type declaration should fail on array elements of different types', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + type B A + a := []B{12, 21} + b := []A{48, 77} + fmt.Println(a[0] + b[1]) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should fail on arrays of different types', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + type B A + a := []B{12, 21} + b := []A{48, 77} + b = a + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declaration should work on functions with matching type return values used for array element assignment', () => { + const code = ` + package main + import "fmt" + + type A int + func help(c A) { + fmt.Println(c) + } + + func help2(a A) A { + return a * 2 + } + + func main() { + a := []A{help2(24), help2(67)} + fmt.Println(a) + } + ` + expect(codeRunner(code).output).toEqual("[48 134]\n") + }) + + test('Same type name on different scopes should be seen as different types', () => { + const code = ` + package main + import "fmt" + + type A int + var a A = 1 + + func main() { + type A int + var b A = 1 + fmt.Println(a + b) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type not in scope but with same name should fail', () => { + const code = ` + package main + import "fmt" + + var a A = 1 + + func main() { + type A int + var b A = 1 + fmt.Println(a + b) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Same type name on different scopes should be seen as different types (multiple layers)', () => { + const code = ` + package main + import "fmt" + + type A int + var a A = 1 + + func main() { + type B A + type A B + var b A = 1 + fmt.Println(b + a) + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Same type name on different scopes should be seen as different types (for loops)', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + var c A = 3 + for i := 0; i < 9; i++ { + type A int + var b A = 2 + fmt.Println(b + c) + } + } + ` + expect(codeRunner(code).error?.type).toEqual("compile") + }) + + test('Type declarations are preserved in loops', () => { + const code = ` + package main + import "fmt" + + func main() { + type A int + var c A = 3 + for i := 0; i < 9; i++ { + var b A = 2 + fmt.Println(b + c) + } + } + ` + expect(codeRunner(code).output).toEqual("5\n5\n5\n5\n5\n5\n5\n5\n5\n") + }) + + test('Type declarations are preserved across functions', () => { + const code = ` + package main + import "fmt" + + type A int + + func help(a A) A { + var b A = a + fmt.Println(b * a) + return b + } + + func main() { + var c A = 14 + var d A = help(c) + fmt.Println(c + d) + fmt.Println(d) + } + ` + expect(codeRunner(code).output).toEqual("196\n28\n14\n") + }) }) diff --git a/src/go-virtual-machine-main/tests/defer.test.ts b/src/go-virtual-machine-main/tests/defer.test.ts index a4f0b86..60623a0 100644 --- a/src/go-virtual-machine-main/tests/defer.test.ts +++ b/src/go-virtual-machine-main/tests/defer.test.ts @@ -1,8 +1,6 @@ import { describe, expect, test } from 'vitest' -import { runCode } from '../virtual-machine' - -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Defer Type Checking', () => { test('Defer on non call should fail.', () => { @@ -25,7 +23,56 @@ describe('Defer Execution', () => { expect(mainRunner(code).output).toEqual('hello\nworld\n!!!\n') }) - test('Defer with wait groups work', () => { + test('Defer argument is evaluated at that line with anonymous function', () => { + const code = ` + a := 3 + defer func(b int) { + fmt.Println(b) + }(a) + a = a + 345 + defer func(){ fmt.Println("world") }() + fmt.Println("hello") + ` + expect(mainRunner(code).output).toEqual('hello\nworld\n3\n') + }) + + test('Defer argument is evaluated at that line with calling a pre-declared function directly', () => { + const code = ` + a := 3 + defer func(b int) { + fmt.Println(b) + }(a) + a = a + 3 + defer fmt.Println(a) + a = a + 345 + fmt.Println("hello") + ` + expect(mainRunner(code).output).toEqual('hello\n6\n3\n') + }) + + test('Defer with wait groups work with a small number of goroutines', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + count := 0 + var wg sync.WaitGroup + for i := 0; i < 30; i++ { + wg.Add(1) + go func() { + defer wg.Done() + count++ + }() + } + wg.Wait() + fmt.Println(count) + } + ` + expect(codeRunner(code).output).toEqual('30\n') + }) + + test('Defer with wait groups work with a large number of goroutines', () => { const code = ` package main import "fmt" @@ -44,6 +91,27 @@ describe('Defer Execution', () => { fmt.Println(count) } ` - expect(runCode(code, 2048).output).toEqual('1000\n') + expect(codeRunner(code).output).toEqual('1000\n') + }) + + test('Defer with mutex work with a small number of goroutines', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + count := 0 + var mu sync.Mutex + for i := 0; i < 10; i++ { + go func() { + mu.Lock() + defer mu.Unlock() + count++ + fmt.Println(count) + }() + } + } + ` + expect(codeRunner(code).output).toEqual('1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n') }) }) diff --git a/src/go-virtual-machine-main/tests/expression.test.ts b/src/go-virtual-machine-main/tests/expression.test.ts index 679cb98..b6b4e58 100644 --- a/src/go-virtual-machine-main/tests/expression.test.ts +++ b/src/go-virtual-machine-main/tests/expression.test.ts @@ -16,4 +16,56 @@ describe('Basic Expression Tests', () => { mainRunner('fmt.Println((2+1 < 3) || (7 == 9%5 + 15/5))').output, ).toEqual('true\n') }) + + test('int literal can act as a float too', () => { + const code = ` + type Age float64 + type Num Age + var x Num = 3.25 + fmt.Println(x + 52) + ` + expect(mainRunner(code).output).toEqual("55.25\n") + }) + + test('float literal can act as an int too if it has no floating point values', () => { + const code = ` + type Age int + type Num Age + var x Num = 12 + fmt.Println(x + 3.00000) + ` + expect(mainRunner(code).output).toEqual("15\n") + }) + + test('Division truncates result when denominator is an int', () => { + const code = ` + var x int = 340 + fmt.Println(100 / 7) + fmt.Println(8000 / x) + ` + expect(mainRunner(code).output).toEqual("14\n23\n") + }) + + test('Division does not truncate result when denominator is a float', () => { + const code = ` + var x float64 = 6400.0 + fmt.Println(100.0 / 8.0) + fmt.Println(800.0 / x) + ` + expect(mainRunner(code).output).toEqual("12.5\n0.125\n") + }) + + test('Binops work on untyped literals with 1 being a float and another being an int', () => { + const code = ` + fmt.Println(80 / 32.0) + fmt.Println(80 * 32.0) + fmt.Println(80 + 32.0) + fmt.Println(80 - 32.0) + fmt.Println(80.0 / 32) + fmt.Println(80.0 * 32) + fmt.Println(80.0 + 32) + fmt.Println(80.0 - 32) + ` + expect(mainRunner(code).output).toEqual("2.5\n2560\n112\n48\n2\n2560\n112\n48") + }) }) diff --git a/src/go-virtual-machine-main/tests/function.test.ts b/src/go-virtual-machine-main/tests/function.test.ts index a64420b..d8ade8a 100644 --- a/src/go-virtual-machine-main/tests/function.test.ts +++ b/src/go-virtual-machine-main/tests/function.test.ts @@ -1,8 +1,6 @@ import { describe, expect, test } from 'vitest' -import { runCode } from '../virtual-machine' - -import { mainRunner } from './utility' +import { codeRunner, mainRunner } from './utility' describe('Function Type Checking', () => { test('Function assignment', () => { @@ -80,7 +78,7 @@ describe('Function Type Checking', () => { fmt.Print(u(6)); } ` - expect(runCode(code, 2048).output).toEqual('6 6') + expect(codeRunner(code).output).toEqual('6 6') }) test('Function with more than 1 return value to be assigned to variables', () => { @@ -97,18 +95,18 @@ describe('Function Type Checking', () => { fmt.Println(b); } ` - expect(runCode(code, 2048).output).toEqual('8\n11\n') + expect(codeRunner(code).output).toEqual('8\n11\n') }) test('Nested function', () => { const code = ` package main import "fmt" - func f(x int) (y int) { + func f(x int) int { return x + 2; } - func g(x int) (y int) { + func g(x int) int { return x + 5; } @@ -116,7 +114,7 @@ describe('Function Type Checking', () => { fmt.Println(g(f(1))); } ` - expect(runCode(code, 2048).output).toEqual('8\n') + expect(codeRunner(code).output).toEqual('8\n') }) }) @@ -134,7 +132,7 @@ describe('Function Execution tests', () => { test('Function Declaration', () => { expect( - runCode( + codeRunner( `package main import "fmt" @@ -149,15 +147,13 @@ describe('Function Execution tests', () => { return x + y + 100 } fmt.Println(f(1, 2)) - }`, - 2048, - ).output, + }`,).output, ).toEqual('103\n') }) test('Function assignment in loop', () => { expect( - runCode( + codeRunner( `package main import "fmt" func main() { @@ -170,15 +166,13 @@ describe('Function Execution tests', () => { } } fmt.Println(f(1, 2)) - }`, - 2048, - ).output, + }`,).output, ).toEqual('8\n') }) test('Function assignment in loop and if', () => { expect( - runCode( + codeRunner( `package main import "fmt" func main() { @@ -193,15 +187,13 @@ describe('Function Execution tests', () => { } } fmt.Println(f(1, 2)) - }`, - 2048, - ).output, + }`,).output, ).toEqual('103\n') }) test('Recursive function', () => { expect( - runCode( + codeRunner( `package main import "fmt" @@ -215,9 +207,7 @@ describe('Function Execution tests', () => { func main() { fmt.Println(f(10)) - }`, - 2048, - ).output, + }`,).output, ).toEqual('10\n') }) @@ -229,7 +219,7 @@ describe('Function Execution tests', () => { test('Closures', () => { expect( - runCode( + codeRunner( `package main import "fmt" @@ -253,9 +243,122 @@ describe('Function Execution tests', () => { fmt.Println(f2(2, 3)) fmt.Println(f2(1, 1)) } - `, - 2048, - ).output, + `,).output, ).toEqual('8\n4\n5\n3\n9\n5\n') }) + + test('Function can reassign variables in parent scope', () => { + expect( + mainRunner(` + x := 0 + func() { + x = 99 + }() + fmt.Println(x) + `).output, + ).toEqual('99\n') + }) + + test('Function works as first class citizens', () => { + expect( + mainRunner(` + q, g := 10, func() int { return q } + fmt.Println(g()) + `).output, + ).toEqual('10\n') + }) + + test('Function works as first class citizens', () => { + expect( + codeRunner(` + package main + import "fmt" + + func f() (int, int, string) { + return 1, 2, "IUCvevfde" + } + + func x() string { + a, b, s := f() + return s + } + + func main() { + e := x() + m, n, o := f() + fmt.Println(e) + fmt.Println(m) + fmt.Println(n) + fmt.Println(o) + } + `).output, + ).toEqual('IUCvevfde\n1\n2\nIUCvevfde\n') + }) + + test('Function works as first class citizens', () => { + expect( + codeRunner(` + package main + import "fmt" + + func f() (int, int, string) { + return 1, 2, "IUCvevfde" + } + + func x(a int, b int, s string) (int, int, string) { + return a * 10, b * 10, s + } + + func main() { + c, d, e := x(f()) + fmt.Println(c) + fmt.Println(d) + fmt.Println(e) + } + `).output, + ).toEqual('10\n20\nIUCvevfde\n') + }) + + test('Function works as first class citizens', () => { + expect( + codeRunner(` + package main + import "fmt" + + func x(a int, b int, s string) (int, int, string) { + return a * 10, b * 10, s + } + + func main() { + c, d, e := x(1, 2, "IUCvevfde") + fmt.Println(c) + fmt.Println(d) + fmt.Println(e) + } + `).output, + ).toEqual('10\n20\nIUCvevfde\n') + }) + + test('Function works as first class citizens', () => { + expect( + codeRunner(` + package main + import "fmt" + + func x(a int, s string) (int, string) { + return a * 10, s + } + + func main() { + d, e := x(3, "IUCvevfde") + c, f := 3, 2 + fmt.Println(c) + fmt.Println(d) + fmt.Println(e) + fmt.Println(f) + fmt.Println(x(3, "IUCvevfde")) + } + `).output, + ).toEqual('3\n30\nIUCvevfde\n2\n30 IUCvevfde\n') + }) }) \ No newline at end of file diff --git a/src/go-virtual-machine-main/tests/heap.test.ts b/src/go-virtual-machine-main/tests/heap.test.ts index 0d7d3e6..d6098a8 100644 --- a/src/go-virtual-machine-main/tests/heap.test.ts +++ b/src/go-virtual-machine-main/tests/heap.test.ts @@ -1,11 +1,13 @@ import { describe, expect, test } from 'vitest' - -import { Heap } from '../virtual-machine/heap' +import { Heap, TAG } from '../virtual-machine/heap' import { ContextNode } from '../virtual-machine/heap/types/context' import { EnvironmentNode, FrameNode, } from '../virtual-machine/heap/types/environment' +import { CompileData, ProgramData } from '../virtual-machine' +import { compileCode, parseCode, runCodeWithHeap } from './utility' +import { BoolNode, IntegerNode } from '../virtual-machine/heap/types/primitives' describe('Heap Tests', () => { test('Get Set Bits', () => { @@ -46,4 +48,88 @@ describe('Heap Tests', () => { heap.allocate(2) expect(() => heap.allocate(4)).toThrow(Error) }) + + test('Array memory allocation for integers', () => { + const code = + ` + package main + import "fmt" + func main() { + a := [10]int{1, 25, 32, 43, 15, 46, 87, 83, 97, 610}; + fmt.Println(a) + } + ` + let compiled = compileCode(code) as CompileData + let heap = new Heap(2048) + runCodeWithHeap(compiled, heap) + let arrayNode = 0 + for (let i = 0; i < 2048; i++) { + if (heap.get_tag(i) === TAG.ARRAY) { + arrayNode = i + break + } + } + let start = heap.get_value(arrayNode).get_children()[0] + expect((heap.get_value(start) as IntegerNode).get_value()).toEqual(1) + expect(start + 2).toEqual(heap.get_value(arrayNode).get_children()[1]) + expect((heap.get_value(start + 2) as IntegerNode).get_value()).toEqual(25) + expect(start + 4).toEqual(heap.get_value(arrayNode).get_children()[2]) + expect((heap.get_value(start + 4) as IntegerNode).get_value()).toEqual(32) + expect(start + 6).toEqual(heap.get_value(arrayNode).get_children()[3]) + expect((heap.get_value(start + 6) as IntegerNode).get_value()).toEqual(43) + expect(start + 8).toEqual(heap.get_value(arrayNode).get_children()[4]) + expect((heap.get_value(start + 8) as IntegerNode).get_value()).toEqual(15) + expect(start + 10).toEqual(heap.get_value(arrayNode).get_children()[5]) + expect((heap.get_value(start + 10) as IntegerNode).get_value()).toEqual(46) + expect(start + 12).toEqual(heap.get_value(arrayNode).get_children()[6]) + expect((heap.get_value(start + 12) as IntegerNode).get_value()).toEqual(87) + expect(start + 14).toEqual(heap.get_value(arrayNode).get_children()[7]) + expect((heap.get_value(start + 14) as IntegerNode).get_value()).toEqual(83) + expect(start + 16).toEqual(heap.get_value(arrayNode).get_children()[8]) + expect((heap.get_value(start + 16) as IntegerNode).get_value()).toEqual(97) + expect(start + 18).toEqual(heap.get_value(arrayNode).get_children()[9]) + expect((heap.get_value(start + 18) as IntegerNode).get_value()).toEqual(610) + }) + + test('Array memory allocation for booleans', () => { + const code = + ` + package main + import "fmt" + func main() { + a := [10]bool{true, true, true, false, true, false, true, false, false, true}; + fmt.Println(a) + } + ` + let compiled = compileCode(code) as CompileData + let heap = new Heap(2048) + runCodeWithHeap(compiled, heap) + let arrayNode = 0 + for (let i = 0; i < 2048; i++) { + if (heap.get_tag(i) === TAG.ARRAY) { + arrayNode = i + break + } + } + let start = heap.get_value(arrayNode).get_children()[0] + expect((heap.get_value(start) as BoolNode).get_value()).toEqual(true) + expect(start + 1).toEqual(heap.get_value(arrayNode).get_children()[1]) + expect((heap.get_value(start + 1) as BoolNode).get_value()).toEqual(true) + expect(start + 2).toEqual(heap.get_value(arrayNode).get_children()[2]) + expect((heap.get_value(start + 2) as BoolNode).get_value()).toEqual(true) + expect(start + 3).toEqual(heap.get_value(arrayNode).get_children()[3]) + expect((heap.get_value(start + 3) as BoolNode).get_value()).toEqual(false) + expect(start + 4).toEqual(heap.get_value(arrayNode).get_children()[4]) + expect((heap.get_value(start + 4) as BoolNode).get_value()).toEqual(true) + expect(start + 5).toEqual(heap.get_value(arrayNode).get_children()[5]) + expect((heap.get_value(start + 5) as BoolNode).get_value()).toEqual(false) + expect(start + 6).toEqual(heap.get_value(arrayNode).get_children()[6]) + expect((heap.get_value(start + 6) as BoolNode).get_value()).toEqual(true) + expect(start + 7).toEqual(heap.get_value(arrayNode).get_children()[7]) + expect((heap.get_value(start + 7) as BoolNode).get_value()).toEqual(false) + expect(start + 8).toEqual(heap.get_value(arrayNode).get_children()[8]) + expect((heap.get_value(start + 8) as BoolNode).get_value()).toEqual(false) + expect(start + 9).toEqual(heap.get_value(arrayNode).get_children()[9]) + expect((heap.get_value(start + 9) as BoolNode).get_value()).toEqual(true) + }) }) diff --git a/src/go-virtual-machine-main/tests/mutex.test.ts b/src/go-virtual-machine-main/tests/mutex.test.ts new file mode 100644 index 0000000..c7bb479 --- /dev/null +++ b/src/go-virtual-machine-main/tests/mutex.test.ts @@ -0,0 +1,140 @@ +import { describe, expect, test } from 'vitest' + +import { codeRunner } from './utility' + +describe('Mutex Type Checking', () => { + test('Mutex should not work without importing sync.', () => { + const code = ` + package main + + func main() { + var a sync.Mutex + } + ` + expect(codeRunner(code).error?.message).toEqual( + 'Variable sync not found', + ) + }) + + test('Assinging a variable of another type to Mutex should fail.', () => { + const code = ` + package main + import "sync" + func main() { + var a sync.Mutex = "hello" + } + ` + expect(codeRunner(code).error?.message).toEqual( + 'Cannot use string as sync.Mutex in variable declaration', + ) + }) + + test('Calling .Lock() with too many arguments should fail.', () => { + const code = ` + package main + import "sync" + func main() { + var a sync.Mutex + a.Lock(1, 2) + } + ` + expect(codeRunner(code).error?.message).toEqual( + 'Too many arguments in function call\nhave (int64, int64)\nwant ()', + ) + }) + + test('Calling invalid functions should fail.', () => { + const code = ` + package main + import "sync" + func main() { + var a sync.Mutex + a.Add(1) + } + ` + expect(codeRunner(code).error?.message).toEqual( + '.Add undefined (type sync.Mutex has no field or method Add)', + ) + }) +}) + +describe('Wait Group Execution', () => { + test('Unlocking an unlocked mutex should panic.', () => { + const code = ` + package main + import "sync" + func main() { + var a sync.Mutex + a.Unlock() + } + ` + expect(codeRunner(code).error?.message).toEqual( + 'Execution Error: sync: unlock of unlocked mutex', + ) + }) + + test('Double locking the same mutex should block.', () => { + const code = ` + package main + import "sync" + func main() { + var a sync.Mutex + a.Lock() + a.Lock() + } + ` + expect(codeRunner(code).error?.message).toEqual( + 'Execution Error: all goroutines are asleep - deadlock!', + ) + }) + + test('Mutex works without unlocking.', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + var mu sync.Mutex + mu.Lock() + fmt.Println("Done") + } + ` + expect(codeRunner(code).output).toEqual('Done\n') + }) + + test('Mutex works with unlocking.', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + var mu sync.Mutex + mu.Lock() + mu.Unlock() + fmt.Println("Done") + } + ` + expect(codeRunner(code).output).toEqual('Done\n') + }) + + test('Mutex works with multiple goroutines', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + count := 0 + var mu sync.Mutex + for i := 0; i < 10; i++ { + go func() { + mu.Lock() + count++ + fmt.Println(count) + mu.Unlock() + }() + } + } + ` + expect(codeRunner(code).output).toEqual('1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n') + }) +}) diff --git a/src/go-virtual-machine-main/tests/parser.test.ts b/src/go-virtual-machine-main/tests/parser.test.ts new file mode 100644 index 0000000..93c8479 --- /dev/null +++ b/src/go-virtual-machine-main/tests/parser.test.ts @@ -0,0 +1,177 @@ +import { describe, expect, test } from 'vitest' + +import { codeRunner, mainRunner } from './utility' + +describe('Import statement syntax check', () => { + test(`Missing bracket for multiple imports with a single + "import" keyword should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt"; "sync" + `).error?.type, + ).toEqual("parse") + }) + + test(`Import statement with comma should throw parsing error`, () => { + expect( + codeRunner(` + package main + import ("fmt", "sync") + `).error?.type, + ).toEqual("parse") + }) + }) + + describe('If statement syntax check', () => { + test(`Missing conditional in if statements should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + if { + fmt.Println("Hi") + } + } + `).error?.type, + ).toEqual("parse") + }) + + test(`Using a function with no boolean returned as a conditional + for if statements should throw compilation error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func yes() { + } + + func main() { + if yes() { + fmt.Println("Hi") + } + } + `).error?.type, + ).toEqual("compile") + }) + + test(`Using a non-boolean as a conditional + for if statements should throw compilation error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + a := 5 + if a { + fmt.Println("Hi") + } + } + `).error?.type, + ).toEqual("compile") + }) + + test(`Missing curly braces for if-blocks should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + if true + } + `).error?.type, + ).toEqual("parse") + }) + + test(`Else statements without if should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + else + } + `).error?.type, + ).toEqual("parse") + }) + + test(`Declaring new variables in if should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + if (var x = true) {} + } + `).error?.type, + ).toEqual("parse") + }) + + test(`Declaring new variables in for loops should throw parsing error`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + for var i = 0; i < 10; i++ {} + } + `).error?.type, + ).toEqual("parse") + }) + test(`Declaring hexadecimal should parse correctly`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + a := 0x789 + b := 0Xfae + fmt.Println(a) + fmt.Println(b) + } + `).output, + ).toEqual("1929\n4014\n") + }) + + test(`Declaring octal should parse correctly`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + a := 0o735 + b := 0O170 + fmt.Println(a) + fmt.Println(b) + } + `).output, + ).toEqual("477\n120\n") + }) + + test(`Declaring binary should parse correctly`, () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + a := 0b111111 + b := 0B101001 + fmt.Println(a) + fmt.Println(b) + } + `).output, + ).toEqual("63\n41\n") + }) + }) + \ No newline at end of file diff --git a/src/go-virtual-machine-main/tests/struct.test.ts b/src/go-virtual-machine-main/tests/struct.test.ts new file mode 100644 index 0000000..1195290 --- /dev/null +++ b/src/go-virtual-machine-main/tests/struct.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, test } from 'vitest' + +import { codeRunner } from './utility' + +describe('Struct tests', () => { + test('Single field line with multiple fields work', () => { + expect( + codeRunner(` + package main + import "fmt" + type A struct { + Age, Age2 int + } + + func main() { + var a A + fmt.Println(a) + } + `).output, + ).toEqual('{0 0}\n') + }) + + test('Multiple (2) field lines work', () => { + expect( + codeRunner(` + package main + import "fmt" + + type A struct { + Age int + Name string + } + + func main() { + var a A + fmt.Println(a) + } + `).output, + ).toEqual('{0 }\n') + }) + + test('Multiple (3) field lines work', () => { + expect( + codeRunner(` + package main + import "fmt" + + type A struct { + Underage bool + Name string + Age int + } + + func main() { + var a A + fmt.Println(a) + } + `).output, + ).toEqual('{false 0}\n') + }) + + test('Short variable declaration of struct works', () => { + expect( + codeRunner(` + package main + import "fmt" + + func main() { + a := struct { + Age, Age2 int + } + fmt.Println(a) + } + `).output, + ).toEqual('{0 0}\n') + }) +}) diff --git a/src/go-virtual-machine-main/tests/utility.ts b/src/go-virtual-machine-main/tests/utility.ts index 74514e2..b596b0a 100644 --- a/src/go-virtual-machine-main/tests/utility.ts +++ b/src/go-virtual-machine-main/tests/utility.ts @@ -1,4 +1,14 @@ -import { runCode } from '../virtual-machine' +import * as seedrandom from 'seedrandom' +import { CompileData, runCode } from '../virtual-machine' +import parser from '../virtual-machine/compiler/parser' +import { SourceFileTokens, TokenLocation } from '../virtual-machine/compiler/tokens' +import { compile_tokens, CompileError } from '../virtual-machine/executor' +import { Instruction } from '../virtual-machine/executor/instructions' +import { Heap } from '../virtual-machine/heap' +import { ContextNode } from '../virtual-machine/heap/types/context' +import { EnvironmentNode, FrameNode } from '../virtual-machine/heap/types/environment' +import { Debugger } from '../virtual-machine/runtime/debugger' +import { Process } from '../virtual-machine/runtime/process' /** Runs the code in a main function */ export const mainRunner = (code: string) => { @@ -9,5 +19,131 @@ export const mainRunner = (code: string) => { ${code} } ` - return runCode(packagedCode, 2048) + return runCode(packagedCode, 2048, true) } + +/** Runs the code in a main function with randomised context switch */ +export const mainRunnerRandom = (code: string) => { + const packagedCode = ` + package main + import "fmt" + func main() { + ${code} + } + ` + return runCode(packagedCode, 2048, false) +} + +/** Runs the code as a whole */ +export const codeRunner = (code: string) => { + return runCode(code, 2048, true) +} + +export const compileCode = ( + source_code: string, +): CompileData => { + let instructions: Instruction[] = [] + let symbols: (TokenLocation | null)[] = [] + let message = "" + let err = "" + let tokens = null + try { + tokens = parser.parse(source_code) as SourceFileTokens + console.log(tokens) + } catch (err) { + message = (err as Error).message + return { + instructions: [], + symbols: [], + output: message, + error: { + message, + type: 'parse', + details: err as string, + }, + visualData: [], + } + } + try { + const temp = compile_tokens(tokens) + instructions = temp.instructions + symbols = temp.symbols + console.log(instructions) + } catch (err) { + message = (err as CompileError).message + } + return { + instructions, + symbols, + output: message, + error: { + message, + type: 'compile', + details: err as string, + }, + visualData: [], + } +} + +export const runCodeWithHeap = ( + compiled: CompileData, + heap: Heap, + deterministic = true, + visualisation = true, +) => { + // Execution. + let instructions = compiled.instructions + let symbols = compiled.symbols + const process = new Process(instructions, 2048, symbols, deterministic, visualisation) + process.instructions = instructions + process.heap = heap + process.contexts = process.heap.contexts + process.context = new ContextNode(process.heap, process.contexts.peek()) + process.stdout = '' + const base_frame = FrameNode.create(0, process.heap) + const base_env = EnvironmentNode.create( + base_frame.addr, + [], + false, + process.heap, + ) + process.context.set_E(base_env.addr) + const randomSeed = Math.random().toString(36).substring(2) + process.generator = seedrandom.default(randomSeed) + process.deterministic = deterministic + process.debug_mode = true + process.debugger = new Debugger(process.heap, process.instructions, symbols) + if (process.debug_mode) + process.debugger.context_id_map.set( + process.context.addr, + process.debugger.context_id++, + ) + process.heap.debugger = process.debugger + const result = process.start() + if (result.errorMessage) { + console.warn(result.errorMessage) + return { + instructions: [], + output: result.errorMessage, + error: { + message: result.errorMessage, + type: 'runtime', + details: result.errorMessage, + }, + visualData: [], + } + } + return { + instructions, + output: result.stdout, + visualData: result.visual_data, + error: undefined, + } +} + +/** Runs the code as a whole with randomised context switch */ +export const codeRunnerRandom = (code: string) => { + return runCode(code, 2048, false) +} + +export { runCode } diff --git a/src/go-virtual-machine-main/tests/waitGroup.test.ts b/src/go-virtual-machine-main/tests/waitGroup.test.ts index 0d6a534..eaa3ff1 100644 --- a/src/go-virtual-machine-main/tests/waitGroup.test.ts +++ b/src/go-virtual-machine-main/tests/waitGroup.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { runCode } from '../virtual-machine' +import { codeRunner } from './utility' describe('Wait Group Type Checking', () => { test('Wait groups should not work without importing sync.', () => { @@ -11,7 +11,7 @@ describe('Wait Group Type Checking', () => { var a sync.WaitGroup } ` - expect(runCode(code, 2048).error?.message).toEqual( + expect(codeRunner(code).error?.message).toEqual( 'Variable sync not found', ) }) @@ -24,7 +24,7 @@ describe('Wait Group Type Checking', () => { var a sync.WaitGroup = "hello" } ` - expect(runCode(code, 2048).error?.message).toEqual( + expect(codeRunner(code).error?.message).toEqual( 'Cannot use string as sync.WaitGroup in variable declaration', ) }) @@ -38,7 +38,7 @@ describe('Wait Group Type Checking', () => { a.Add(1, 2) } ` - expect(runCode(code, 2048).error?.message).toEqual( + expect(codeRunner(code).error?.message).toEqual( 'Too many arguments in function call\nhave (int64, int64)\nwant (int64)', ) }) @@ -54,7 +54,7 @@ describe('Wait Group Execution', () => { a.Add(-5) } ` - expect(runCode(code, 2048).error?.message).toEqual( + expect(codeRunner(code).error?.message).toEqual( 'Execution Error: sync: negative WaitGroup counter.', ) }) @@ -70,12 +70,34 @@ describe('Wait Group Execution', () => { a.Done() } ` - expect(runCode(code, 2048).error?.message).toEqual( + expect(codeRunner(code).error?.message).toEqual( 'Execution Error: sync: negative WaitGroup counter.', ) }) - test('Waiting works.', () => { + test('Waiting works with a small number of goroutines.', () => { + const code = ` + package main + import "fmt" + import "sync" + func main() { + count := 0 + var wg sync.WaitGroup + for i := 0; i < 30; i++ { + wg.Add(1) + go func() { + count++ + wg.Done() + }() + } + wg.Wait() + fmt.Println(count) + } + ` + expect(codeRunner(code).output).toEqual('30\n') + }) + + test('Waiting works with a large number of goroutines.', () => { const code = ` package main import "fmt" @@ -94,6 +116,6 @@ describe('Wait Group Execution', () => { fmt.Println(count) } ` - expect(runCode(code, 2048).output).toEqual('1000\n') + expect(codeRunner(code).output).toEqual('1000\n') }) }) diff --git a/src/go-virtual-machine-main/virtual-machine/parser/golang_parser.js b/src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.js similarity index 89% rename from src/go-virtual-machine-main/virtual-machine/parser/golang_parser.js rename to src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.js index f8e297f..6ac3c79 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/golang_parser.js +++ b/src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.js @@ -10,11 +10,12 @@ StringLiteralToken, BinaryOperator, UnaryOperator, - SourceFileToken, + SourceFileTokens, ImportToken, FunctionDeclarationToken, VariableDeclarationToken, ConstantDeclarationToken, + TypeDeclarationToken, PrimaryExpressionToken, AssignmentStatementToken, IdentifierToken, @@ -29,8 +30,10 @@ ForStatementToken, DeferStatementToken, PrimitiveTypeToken, + DeclaredTypeToken, ArrayTypeToken, SliceTypeToken, + StructTypeToken, FunctionTypeToken, MapTypeToken, ChannelTypeToken, @@ -238,85 +241,85 @@ function peg$parse(input, options) { var peg$c3 = "/*"; var peg$c4 = "*/"; var peg$c5 = "0"; - var peg$c6 = "b"; - var peg$c7 = "."; - var peg$c8 = "`"; - var peg$c9 = "\""; - var peg$c10 = "("; - var peg$c11 = ")"; - var peg$c12 = "["; - var peg$c13 = "]"; - var peg$c14 = "struct"; - var peg$c15 = "{"; - var peg$c16 = ";"; - var peg$c17 = "}"; - var peg$c18 = "*"; - var peg$c19 = "func"; - var peg$c20 = ","; - var peg$c21 = "interface"; - var peg$c22 = "|"; - var peg$c23 = "~"; - var peg$c24 = "map"; - var peg$c25 = "chan"; - var peg$c26 = "<-"; - var peg$c27 = "const"; - var peg$c28 = "="; - var peg$c29 = "type"; - var peg$c30 = "var"; - var peg$c31 = ":="; - var peg$c32 = ":"; - var peg$c33 = "=="; - var peg$c34 = "!="; - var peg$c35 = "<="; - var peg$c36 = ">="; - var peg$c37 = "<"; - var peg$c38 = "-"; - var peg$c39 = ">"; - var peg$c40 = "+"; - var peg$c41 = "^"; - var peg$c42 = "/"; - var peg$c43 = "%"; - var peg$c44 = "<<"; - var peg$c45 = ">>"; - var peg$c46 = "&"; - var peg$c47 = "&^"; - var peg$c48 = "||"; - var peg$c49 = "&&"; - var peg$c50 = "!"; - var peg$c51 = "++"; - var peg$c52 = "--"; - var peg$c53 = "if"; - var peg$c54 = "else"; - var peg$c55 = "switch"; - var peg$c56 = "case"; - var peg$c57 = "default"; - var peg$c58 = "for"; - var peg$c59 = "range"; - var peg$c60 = "go"; - var peg$c61 = "select"; - var peg$c62 = "return"; - var peg$c63 = "break"; - var peg$c64 = "continue"; - var peg$c65 = "goto"; - var peg$c66 = "fallthrough"; - var peg$c67 = "defer"; - var peg$c68 = "package"; - var peg$c69 = "import"; + var peg$c6 = "."; + var peg$c7 = "`"; + var peg$c8 = "\""; + var peg$c9 = "("; + var peg$c10 = ")"; + var peg$c11 = "["; + var peg$c12 = "]"; + var peg$c13 = "struct"; + var peg$c14 = "{"; + var peg$c15 = ";"; + var peg$c16 = "}"; + var peg$c17 = "*"; + var peg$c18 = "func"; + var peg$c19 = ","; + var peg$c20 = "interface"; + var peg$c21 = "|"; + var peg$c22 = "~"; + var peg$c23 = "map"; + var peg$c24 = "chan"; + var peg$c25 = "<-"; + var peg$c26 = "const"; + var peg$c27 = "="; + var peg$c28 = "type"; + var peg$c29 = "var"; + var peg$c30 = ":="; + var peg$c31 = ":"; + var peg$c32 = "=="; + var peg$c33 = "!="; + var peg$c34 = "<="; + var peg$c35 = ">="; + var peg$c36 = "<"; + var peg$c37 = "-"; + var peg$c38 = ">"; + var peg$c39 = "+"; + var peg$c40 = "^"; + var peg$c41 = "/"; + var peg$c42 = "%"; + var peg$c43 = "<<"; + var peg$c44 = ">>"; + var peg$c45 = "&"; + var peg$c46 = "&^"; + var peg$c47 = "||"; + var peg$c48 = "&&"; + var peg$c49 = "!"; + var peg$c50 = "++"; + var peg$c51 = "--"; + var peg$c52 = "if"; + var peg$c53 = "else"; + var peg$c54 = "switch"; + var peg$c55 = "case"; + var peg$c56 = "default"; + var peg$c57 = "for"; + var peg$c58 = "range"; + var peg$c59 = "go"; + var peg$c60 = "select"; + var peg$c61 = "return"; + var peg$c62 = "break"; + var peg$c63 = "continue"; + var peg$c64 = "goto"; + var peg$c65 = "fallthrough"; + var peg$c66 = "defer"; + var peg$c67 = "package"; + var peg$c68 = "import"; var peg$r0 = /^[ \t\r\n]/; var peg$r1 = /^[0-9]/; var peg$r2 = /^[0-1]/; var peg$r3 = /^[0-7]/; var peg$r4 = /^[0-9a-fA-F]/; - var peg$r5 = /^[oO]/; - var peg$r6 = /^[1-9]/; - var peg$r7 = /^[xX]/; - var peg$r8 = /^[eE]/; - var peg$r9 = /^[+\-]/; - var peg$r10 = /^[^`]/; - var peg$r11 = /^[^\n"]/; - var peg$r12 = /^[a-zA-Z]/; - var peg$r13 = /^[*+]/; + var peg$r5 = /^[bB]/; + var peg$r6 = /^[oO]/; + var peg$r7 = /^[1-9]/; + var peg$r8 = /^[xX]/; + var peg$r9 = /^[eE]/; + var peg$r10 = /^[+\-]/; + var peg$r11 = /^[^`]/; + var peg$r12 = /^[^\n"]/; + var peg$r13 = /^[a-zA-Z]/; + var peg$r14 = /^[*+\-\/]/; var peg$e0 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$e1 = peg$literalExpectation("\n", false); @@ -330,7 +333,7 @@ function peg$parse(input, options) { var peg$e9 = peg$literalExpectation("/*", false); var peg$e10 = peg$literalExpectation("*/", false); var peg$e11 = peg$literalExpectation("0", false); - var peg$e12 = peg$literalExpectation("b", false); + var peg$e12 = peg$classExpectation(["b", "B"], false, false); var peg$e13 = peg$classExpectation(["o", "O"], false, false); var peg$e14 = peg$classExpectation([["1", "9"]], false, false); var peg$e15 = peg$classExpectation(["x", "X"], false, false); @@ -385,7 +388,7 @@ function peg$parse(input, options) { var peg$e64 = peg$literalExpectation("!", false); var peg$e65 = peg$literalExpectation("++", false); var peg$e66 = peg$literalExpectation("--", false); - var peg$e67 = peg$classExpectation(["*", "+"], false, false); + var peg$e67 = peg$classExpectation(["*", "+", "-", "/"], false, false); var peg$e68 = peg$literalExpectation("if", false); var peg$e69 = peg$literalExpectation("else", false); var peg$e70 = peg$literalExpectation("switch", false); @@ -409,113 +412,117 @@ function peg$parse(input, options) { var peg$f2 = function(char) { return char.match(/^\p{N}$/u) }; var peg$f3 = function(iden) { return IdentifierToken.isValidIdentifier(iden) }; var peg$f4 = function(iden) { return new IdentifierToken(location(), iden) }; - var peg$f5 = function(number) { return IntegerLiteralToken.fromSource(location(), number, 2) }; - var peg$f6 = function(number) { return IntegerLiteralToken.fromSource(location(), number, 8) }; - var peg$f7 = function(number) { return IntegerLiteralToken.fromSource(location(), number, 10) }; - var peg$f8 = function(number) { return IntegerLiteralToken.fromSource(location(), number, 16) }; + var peg$f5 = function(number) { return IntegerLiteralToken.fromSource(location(), number[3], 2) }; + var peg$f6 = function(number) { return IntegerLiteralToken.fromSource(location(), number[3], 8) }; + var peg$f7 = function(number) { return IntegerLiteralToken.fromSource(location(), number[3], 16) }; + var peg$f8 = function(number) { return IntegerLiteralToken.fromSource(location(), number, 10) }; var peg$f9 = function(number) { return FloatLiteralToken.fromSource(location(), number); }; var peg$f10 = function(str) { return StringLiteralToken.fromSourceRaw(location(), str) }; var peg$f11 = function(str) { return StringLiteralToken.fromSourceInterpreted(location(), str) }; - var peg$f12 = function(iden) { return PrimitiveTypeToken.isPrimitive(iden.identifier) }; - var peg$f13 = function(iden) { return new PrimitiveTypeToken(location(), iden.identifier) }; - var peg$f14 = function(length, element) { return new ArrayTypeToken(location(), element, length) }; - var peg$f15 = function(element) { return new SliceTypeToken(location(), element) }; - var peg$f16 = function(params, result) { return new FunctionTypeToken(location(), params, result) }; - var peg$f17 = function(type) { return [{ type }] }; - var peg$f18 = function(parameters) { return parameters ?? [] }; - var peg$f19 = function(head, tail) { return [head, ...tail].flat()}; - var peg$f20 = function(identifiers, type) { return identifiers == null || identifiers.length === 0 + var peg$f12 = function(iden) { return PrimitiveTypeToken.isPrimitive(iden.identifier) + ? new PrimitiveTypeToken(location(), iden.identifier) + : new DeclaredTypeToken(location(), iden.identifier)}; + var peg$f13 = function(length, element) { return new ArrayTypeToken(location(), element, length) }; + var peg$f14 = function(element) { return new SliceTypeToken(location(), element) }; + var peg$f15 = function(fields) { return new StructTypeToken(location(), [...fields].flat()) }; + var peg$f16 = function(list, type) { return {list, type} }; + var peg$f17 = function(params, result) { return new FunctionTypeToken(location(), params, result) }; + var peg$f18 = function(type) { return [{ type }] }; + var peg$f19 = function(parameters) { return parameters ?? [] }; + var peg$f20 = function(head, tail) { return [head, ...tail].flat()}; + var peg$f21 = function(identifiers, type) { return identifiers == null || identifiers.length === 0 ? [{ identifier: null, type }] : identifiers.map(iden => ({ identifier: iden.identifier, type })) }; - var peg$f21 = function(type) { return [{ identifier: null, type }] }; - var peg$f22 = function(key, element) { return new MapTypeToken(location(), key, element) }; - var peg$f23 = function(element) { return new ChannelTypeToken(location(), element, false, true) }; - var peg$f24 = function(element) { return new ChannelTypeToken(location(), element, true, false) }; - var peg$f25 = function(element) { return new ChannelTypeToken(location(), element, true, true) }; - var peg$f26 = function(statements) { return new BlockToken(location(), statements) }; - var peg$f27 = function(identifiers, varType, expressions) { return { varType, expressions } }; - var peg$f28 = function(identifiers, rest) { return new ConstantDeclarationToken(location(), identifiers, rest.expressions, rest.varType) }; - var peg$f29 = function(head, tail) { return [head, ...tail] }; + var peg$f22 = function(type) { return [{ identifier: null, type }] }; + var peg$f23 = function(key, element) { return new MapTypeToken(location(), key, element) }; + var peg$f24 = function(element) { return new ChannelTypeToken(location(), element, false, true) }; + var peg$f25 = function(element) { return new ChannelTypeToken(location(), element, true, false) }; + var peg$f26 = function(element) { return new ChannelTypeToken(location(), element, true, true) }; + var peg$f27 = function(statements) { return new BlockToken(location(), statements) }; + var peg$f28 = function(identifiers, varType, expressions) { return { varType, expressions } }; + var peg$f29 = function(identifiers, rest) { return new ConstantDeclarationToken(location(), identifiers, rest.expressions, rest.varType) }; var peg$f30 = function(head, tail) { return [head, ...tail] }; - var peg$f31 = function(identifiers, varType, expressions) { return {varType, expressions} }; - var peg$f32 = function(identifiers, expressions) { return {varType: undefined, expressions} }; - var peg$f33 = function(identifiers, rest) { return new VariableDeclarationToken(location(), identifiers, rest.varType, rest.expressions) }; - var peg$f34 = function(identifiers, expressions) { return new ShortVariableDeclarationToken(location(), identifiers, expressions) }; - var peg$f35 = function(name, signature, body) { return new FunctionDeclarationToken(location(), name, new FunctionLiteralToken(location(), signature, body)) }; - var peg$f36 = function(pkg, iden) { return new QualifiedIdentifierToken(location(), pkg.identifier, iden.identifier) }; - var peg$f37 = function(type, value) { return new ArrayLiteralToken(location(), type, value) }; - var peg$f38 = function(type, value) { return new SliceLiteralToken(location(), type, value) }; - var peg$f39 = function(elements) { return new LiteralValueToken(location(), elements ?? []) }; - var peg$f40 = function(head, rest) { return [head, ...rest] }; - var peg$f41 = function(signature, body) { return new FunctionLiteralToken(location(), signature, body) }; - var peg$f42 = function(operand, rest) { return new PrimaryExpressionToken(location(), operand, rest) }; - var peg$f43 = function(identifier) { return new SelectorToken(location(), identifier.identifier) }; - var peg$f44 = function(expr) { return new IndexToken(location(), expr) }; - var peg$f45 = function(from, to) { return new SliceToken(location(), from, to) }; - var peg$f46 = function(exprs) { return new CallToken(location(), exprs) }; - var peg$f47 = function(name, type, args) { return BuiltinCallToken.validNames.includes(name) && BuiltinCallToken.namesThatTakeType.includes(name) }; - var peg$f48 = function(name, type, args) { return new BuiltinCallToken(location(), name, type, args ?? []) }; - var peg$f49 = function(name, args) { return BuiltinCallToken.validNames.includes(name) && !BuiltinCallToken.namesThatTakeType.includes(name) }; - var peg$f50 = function(name, args) { return new BuiltinCallToken(location(), name, null, args ?? []) }; - var peg$f51 = function(rest, right) { return leftPrecTree(rest, right) }; - var peg$f52 = function(rest, right) { return leftPrecTree(rest, right) }; + var peg$f31 = function(head, tail) { return [head, ...tail] }; + var peg$f32 = function(identifier, type) { return new TypeDeclarationToken(location(), identifier, type, undefined) }; + var peg$f33 = function(identifiers, varType, expressions) { return {varType, expressions} }; + var peg$f34 = function(identifiers, expressions) { return {varType: undefined, expressions} }; + var peg$f35 = function(identifiers, rest) { return new VariableDeclarationToken(location(), identifiers, rest.varType, rest.expressions) }; + var peg$f36 = function(identifiers, expressions) { return new ShortVariableDeclarationToken(location(), identifiers, undefined, expressions) }; + var peg$f37 = function(name, signature, body) { return new FunctionDeclarationToken(location(), name, new FunctionLiteralToken(location(), signature, body)) }; + var peg$f38 = function(pkg, iden) { return new QualifiedIdentifierToken(location(), pkg.identifier, iden.identifier) }; + var peg$f39 = function(type, value) { return new ArrayLiteralToken(location(), type, value) }; + var peg$f40 = function(type, value) { return new SliceLiteralToken(location(), type, value) }; + var peg$f41 = function(elements) { return new LiteralValueToken(location(), elements ?? []) }; + var peg$f42 = function(head, rest) { return [head, ...rest] }; + var peg$f43 = function(signature, body) { return new FunctionLiteralToken(location(), signature, body) }; + var peg$f44 = function(operand, rest) { return new PrimaryExpressionToken(location(), operand, rest) }; + var peg$f45 = function(identifier) { return new SelectorToken(location(), identifier.identifier) }; + var peg$f46 = function(expr) { return new IndexToken(location(), expr) }; + var peg$f47 = function(from, to) { return new SliceToken(location(), from, to) }; + var peg$f48 = function(exprs) { return new CallToken(location(), exprs) }; + var peg$f49 = function(name, type, args) { return BuiltinCallToken.validNames.includes(name) && BuiltinCallToken.namesThatTakeType.includes(name) }; + var peg$f50 = function(name, type, args) { return new BuiltinCallToken(location(), name, type, args ?? []) }; + var peg$f51 = function(name, args) { return BuiltinCallToken.validNames.includes(name) && !BuiltinCallToken.namesThatTakeType.includes(name) }; + var peg$f52 = function(name, args) { return new BuiltinCallToken(location(), name, null, args ?? []) }; var peg$f53 = function(rest, right) { return leftPrecTree(rest, right) }; var peg$f54 = function(rest, right) { return leftPrecTree(rest, right) }; var peg$f55 = function(rest, right) { return leftPrecTree(rest, right) }; - var peg$f56 = function(op, expr) { return op(expr) }; - var peg$f57 = function() { return BinaryOperator.fromSource(location(), "equal") }; - var peg$f58 = function() { return BinaryOperator.fromSource(location(), "not_equal") }; - var peg$f59 = function() { return BinaryOperator.fromSource(location(), "less_or_equal") }; - var peg$f60 = function() { return BinaryOperator.fromSource(location(), "greater_or_equal") }; - var peg$f61 = function() { return BinaryOperator.fromSource(location(), "less") }; - var peg$f62 = function() { return BinaryOperator.fromSource(location(), "greater") }; - var peg$f63 = function() { return BinaryOperator.fromSource(location(), "sum") }; - var peg$f64 = function() { return BinaryOperator.fromSource(location(), "difference") }; - var peg$f65 = function() { return BinaryOperator.fromSource(location(), "bitwise_or") }; - var peg$f66 = function() { return BinaryOperator.fromSource(location(), "bitwise_xor") }; - var peg$f67 = function() { return BinaryOperator.fromSource(location(), "product") }; - var peg$f68 = function() { return BinaryOperator.fromSource(location(), "quotient") }; - var peg$f69 = function() { return BinaryOperator.fromSource(location(), "remainder") }; - var peg$f70 = function() { return BinaryOperator.fromSource(location(), "left_shift") }; - var peg$f71 = function() { return BinaryOperator.fromSource(location(), "right_shift") }; - var peg$f72 = function() { return BinaryOperator.fromSource(location(), "bitwise_and") }; - var peg$f73 = function() { return BinaryOperator.fromSource(location(), "bit_clear") }; - var peg$f74 = function() { return BinaryOperator.fromSource(location(), "conditional_or") }; - var peg$f75 = function() { return BinaryOperator.fromSource(location(), "conditional_and") }; - var peg$f76 = function() { return UnaryOperator.fromSource(location(), "plus") }; - var peg$f77 = function() { return UnaryOperator.fromSource(location(), "negation") }; - var peg$f78 = function() { return UnaryOperator.fromSource(location(), "not") }; - var peg$f79 = function() { return UnaryOperator.fromSource(location(), "bitwise_complement") }; - var peg$f80 = function() { return UnaryOperator.fromSource(location(), "indirection") }; - var peg$f81 = function() { return UnaryOperator.fromSource(location(), "address") }; - var peg$f82 = function() { return UnaryOperator.fromSource(location(), "receive") }; - var peg$f83 = function(channel, value) { return new SendStatementToken(location(), channel, value) }; - var peg$f84 = function(expression, op) { return new IncDecStatementToken(location(), expression, op) }; - var peg$f85 = function(left, op, right) { return new AssignmentStatementToken(location(), left, op, right) }; - var peg$f86 = function(init, pred, cons, alt) { return new IfStatementToken(location(), init, pred, cons, alt) }; - var peg$f87 = function(init, expr, cases) { return new SwitchStatementToken(location(), init, expr, cases ) }; - var peg$f88 = function(statements) { return new SwitchCaseToken(location(), null, statements) }; - var peg$f89 = function(exprs, statements) { return new SwitchCaseToken(location(), exprs, statements) }; - var peg$f90 = function(cond) { return {init: undefined, cond, post: undefined }}; - var peg$f91 = function(clause, body) { return new ForStatementToken(location(), clause?.init, clause?.cond, clause?.post, body)}; - var peg$f92 = function(init, cond, post) { return { init: init ?? undefined, cond: cond ?? undefined, post: post ?? undefined } }; - var peg$f93 = function(expr) { return GoStatementToken.isValidGoroutine(expr) }; - var peg$f94 = function(expr) { return new GoStatementToken(location(), expr) }; - var peg$f95 = function(clauses) { return new SelectStatementToken(location(), clauses ?? []) }; - var peg$f96 = function(predicate, body) { return new CommunicationClauseToken(location(), predicate, body) }; - var peg$f97 = function(identifiers, expr) { return ReceiveStatementToken.isReceiveStatement(identifiers) }; - var peg$f98 = function(identifiers, expr) { return new ReceiveStatementToken(location(), true, identifiers, expr) }; + var peg$f56 = function(rest, right) { return leftPrecTree(rest, right) }; + var peg$f57 = function(rest, right) { return leftPrecTree(rest, right) }; + var peg$f58 = function(op, expr) { return op(expr) }; + var peg$f59 = function() { return BinaryOperator.fromSource(location(), "equal") }; + var peg$f60 = function() { return BinaryOperator.fromSource(location(), "not_equal") }; + var peg$f61 = function() { return BinaryOperator.fromSource(location(), "less_or_equal") }; + var peg$f62 = function() { return BinaryOperator.fromSource(location(), "greater_or_equal") }; + var peg$f63 = function() { return BinaryOperator.fromSource(location(), "less") }; + var peg$f64 = function() { return BinaryOperator.fromSource(location(), "greater") }; + var peg$f65 = function() { return BinaryOperator.fromSource(location(), "sum") }; + var peg$f66 = function() { return BinaryOperator.fromSource(location(), "difference") }; + var peg$f67 = function() { return BinaryOperator.fromSource(location(), "bitwise_or") }; + var peg$f68 = function() { return BinaryOperator.fromSource(location(), "bitwise_xor") }; + var peg$f69 = function() { return BinaryOperator.fromSource(location(), "product") }; + var peg$f70 = function() { return BinaryOperator.fromSource(location(), "quotient") }; + var peg$f71 = function() { return BinaryOperator.fromSource(location(), "remainder") }; + var peg$f72 = function() { return BinaryOperator.fromSource(location(), "left_shift") }; + var peg$f73 = function() { return BinaryOperator.fromSource(location(), "right_shift") }; + var peg$f74 = function() { return BinaryOperator.fromSource(location(), "bitwise_and") }; + var peg$f75 = function() { return BinaryOperator.fromSource(location(), "bit_clear") }; + var peg$f76 = function() { return BinaryOperator.fromSource(location(), "conditional_or") }; + var peg$f77 = function() { return BinaryOperator.fromSource(location(), "conditional_and") }; + var peg$f78 = function() { return UnaryOperator.fromSource(location(), "plus") }; + var peg$f79 = function() { return UnaryOperator.fromSource(location(), "negation") }; + var peg$f80 = function() { return UnaryOperator.fromSource(location(), "not") }; + var peg$f81 = function() { return UnaryOperator.fromSource(location(), "bitwise_complement") }; + var peg$f82 = function() { return UnaryOperator.fromSource(location(), "indirection") }; + var peg$f83 = function() { return UnaryOperator.fromSource(location(), "address") }; + var peg$f84 = function() { return UnaryOperator.fromSource(location(), "receive") }; + var peg$f85 = function(channel, value) { return new SendStatementToken(location(), channel, value) }; + var peg$f86 = function(expression, op) { return new IncDecStatementToken(location(), expression, op) }; + var peg$f87 = function(left, op, right) { return new AssignmentStatementToken(location(), left, op, right) }; + var peg$f88 = function(init, pred, cons, alt) { return new IfStatementToken(location(), init, pred, cons, alt) }; + var peg$f89 = function(init, expr, cases) { return new SwitchStatementToken(location(), init, expr, cases ) }; + var peg$f90 = function(statements) { return new SwitchCaseToken(location(), null, statements) }; + var peg$f91 = function(exprs, statements) { return new SwitchCaseToken(location(), exprs, statements) }; + var peg$f92 = function(cond) { return {init: undefined, cond, post: undefined }}; + var peg$f93 = function(clause, body) { return new ForStatementToken(location(), clause?.init, clause?.cond, clause?.post, body)}; + var peg$f94 = function(init, cond, post) { return { init: init ?? undefined, cond: cond ?? undefined, post: post ?? undefined } }; + var peg$f95 = function(expr) { return GoStatementToken.isValidGoroutine(expr) }; + var peg$f96 = function(expr) { return new GoStatementToken(location(), expr) }; + var peg$f97 = function(clauses) { return new SelectStatementToken(location(), clauses ?? []) }; + var peg$f98 = function(predicate, body) { return new CommunicationClauseToken(location(), predicate, body) }; var peg$f99 = function(identifiers, expr) { return ReceiveStatementToken.isReceiveStatement(identifiers) }; - var peg$f100 = function(identifiers, expr) { return new ReceiveStatementToken(location(), false, identifiers, expr) }; - var peg$f101 = function(expr) { return expr instanceof UnaryOperator && expr.name === 'receive' }; - var peg$f102 = function(expr) { return expr }; - var peg$f103 = function(returns) { return new ReturnStatementToken(location(), returns) }; - var peg$f104 = function() { return new BreakStatementToken(location()) }; - var peg$f105 = function() { return new ContinueStatementToken(location()) }; - var peg$f106 = function() { return new FallthroughStatementToken(location()) }; - var peg$f107 = function(expression) { return new DeferStatementToken(location(), expression) }; - var peg$f108 = function(pkg, imports, declarations) { return new SourceFileToken(location(), pkg, imports, declarations) }; - var peg$f109 = function(name, path) { return new ImportToken(location(), path, name) }; + var peg$f100 = function(identifiers, expr) { return new ReceiveStatementToken(location(), true, identifiers, expr) }; + var peg$f101 = function(identifiers, expr) { return ReceiveStatementToken.isReceiveStatement(identifiers) }; + var peg$f102 = function(identifiers, expr) { return new ReceiveStatementToken(location(), false, identifiers, expr) }; + var peg$f103 = function(expr) { return expr instanceof UnaryOperator && expr.name === 'receive' }; + var peg$f104 = function(expr) { return expr }; + var peg$f105 = function(returns) { return new ReturnStatementToken(location(), returns) }; + var peg$f106 = function() { return new BreakStatementToken(location()) }; + var peg$f107 = function() { return new ContinueStatementToken(location()) }; + var peg$f108 = function() { return new FallthroughStatementToken(location()) }; + var peg$f109 = function(expression) { return new DeferStatementToken(location(), expression) }; + var peg$f110 = function(pkg, imports, declarations) { return new SourceFileTokens(location(), pkg, imports, declarations) }; + var peg$f111 = function(name, path) { return new ImportToken(location(), path, name) }; var peg$currPos = options.peg$currPos | 0; var peg$savedPos = peg$currPos; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -1128,7 +1135,7 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = peg$parsedecimal_lit(); + s1 = peg$parsehex_lit(); if (s1 !== peg$FAILED) { peg$savedPos = s0; s1 = peg$f7(s1); @@ -1136,7 +1143,7 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = peg$parsehex_lit(); + s1 = peg$parsedecimal_lit(); if (s1 !== peg$FAILED) { peg$savedPos = s0; s1 = peg$f8(s1); @@ -1150,7 +1157,7 @@ function peg$parse(input, options) { } function peg$parsebinary_lit() { - var s0, s1, s2, s3, s4, s5; + var s0, s1, s2, s3, s4, s5, s6; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 48) { @@ -1161,8 +1168,8 @@ function peg$parse(input, options) { if (peg$silentFails === 0) { peg$fail(peg$e11); } } if (s1 !== peg$FAILED) { - if (input.charCodeAt(peg$currPos) === 98) { - s2 = peg$c6; + s2 = input.charAt(peg$currPos); + if (peg$r5.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; @@ -1180,7 +1187,16 @@ function peg$parse(input, options) { s3 = null; } s4 = peg$currPos; - s5 = peg$parsebinary_digits(); + s5 = []; + s6 = peg$parsebinary_digits(); + if (s6 !== peg$FAILED) { + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = peg$parsebinary_digits(); + } + } else { + s5 = peg$FAILED; + } if (s5 !== peg$FAILED) { s4 = input.substring(s4, peg$currPos); } else { @@ -1206,7 +1222,7 @@ function peg$parse(input, options) { } function peg$parseoctal_lit() { - var s0, s1, s2, s3, s4, s5; + var s0, s1, s2, s3, s4, s5, s6; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 48) { @@ -1218,35 +1234,46 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = input.charAt(peg$currPos); - if (peg$r5.test(s2)) { + if (peg$r6.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e13); } } - if (s2 === peg$FAILED) { - s2 = null; - } - if (input.charCodeAt(peg$currPos) === 95) { - s3 = peg$c1; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e3); } - } - if (s3 === peg$FAILED) { - s3 = null; - } - s4 = peg$currPos; - s5 = peg$parseoctal_digits(); - if (s5 !== peg$FAILED) { - s4 = input.substring(s4, peg$currPos); - } else { - s4 = s5; - } - if (s4 !== peg$FAILED) { - s1 = [s1, s2, s3, s4]; - s0 = s1; + if (s2 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 95) { + s3 = peg$c1; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e3); } + } + if (s3 === peg$FAILED) { + s3 = null; + } + s4 = peg$currPos; + s5 = []; + s6 = peg$parseoctal_digits(); + if (s6 !== peg$FAILED) { + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = peg$parseoctal_digits(); + } + } else { + s5 = peg$FAILED; + } + if (s5 !== peg$FAILED) { + s4 = input.substring(s4, peg$currPos); + } else { + s4 = s5; + } + if (s4 !== peg$FAILED) { + s1 = [s1, s2, s3, s4]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1265,7 +1292,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$currPos; s2 = input.charAt(peg$currPos); - if (peg$r6.test(s2)) { + if (peg$r7.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; @@ -1311,7 +1338,7 @@ function peg$parse(input, options) { } function peg$parsehex_lit() { - var s0, s1, s2, s3, s4, s5; + var s0, s1, s2, s3, s4, s5, s6; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 48) { @@ -1323,7 +1350,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = input.charAt(peg$currPos); - if (peg$r7.test(s2)) { + if (peg$r8.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; @@ -1341,7 +1368,16 @@ function peg$parse(input, options) { s3 = null; } s4 = peg$currPos; - s5 = peg$parsehex_digits(); + s5 = []; + s6 = peg$parsehex_digits(); + if (s6 !== peg$FAILED) { + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = peg$parsehex_digits(); + } + } else { + s5 = peg$FAILED; + } if (s5 !== peg$FAILED) { s4 = input.substring(s4, peg$currPos); } else { @@ -1625,7 +1661,7 @@ function peg$parse(input, options) { s1 = peg$parsedecimal_digits(); if (s1 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 46) { - s2 = peg$c7; + s2 = peg$c6; peg$currPos++; } else { s2 = peg$FAILED; @@ -1669,7 +1705,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s1 = peg$c7; + s1 = peg$c6; peg$currPos++; } else { s1 = peg$FAILED; @@ -1703,7 +1739,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.charAt(peg$currPos); - if (peg$r8.test(s1)) { + if (peg$r9.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; @@ -1711,7 +1747,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = input.charAt(peg$currPos); - if (peg$r9.test(s2)) { + if (peg$r10.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; @@ -1752,7 +1788,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 96) { - s1 = peg$c8; + s1 = peg$c7; peg$currPos++; } else { s1 = peg$FAILED; @@ -1762,7 +1798,7 @@ function peg$parse(input, options) { s2 = peg$currPos; s3 = []; s4 = input.charAt(peg$currPos); - if (peg$r10.test(s4)) { + if (peg$r11.test(s4)) { peg$currPos++; } else { s4 = peg$FAILED; @@ -1771,7 +1807,7 @@ function peg$parse(input, options) { while (s4 !== peg$FAILED) { s3.push(s4); s4 = input.charAt(peg$currPos); - if (peg$r10.test(s4)) { + if (peg$r11.test(s4)) { peg$currPos++; } else { s4 = peg$FAILED; @@ -1780,7 +1816,7 @@ function peg$parse(input, options) { } s2 = input.substring(s2, peg$currPos); if (input.charCodeAt(peg$currPos) === 96) { - s3 = peg$c8; + s3 = peg$c7; peg$currPos++; } else { s3 = peg$FAILED; @@ -1806,7 +1842,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c9; + s1 = peg$c8; peg$currPos++; } else { s1 = peg$FAILED; @@ -1816,7 +1852,7 @@ function peg$parse(input, options) { s2 = peg$currPos; s3 = []; s4 = input.charAt(peg$currPos); - if (peg$r11.test(s4)) { + if (peg$r12.test(s4)) { peg$currPos++; } else { s4 = peg$FAILED; @@ -1825,7 +1861,7 @@ function peg$parse(input, options) { while (s4 !== peg$FAILED) { s3.push(s4); s4 = input.charAt(peg$currPos); - if (peg$r11.test(s4)) { + if (peg$r12.test(s4)) { peg$currPos++; } else { s4 = peg$FAILED; @@ -1834,7 +1870,7 @@ function peg$parse(input, options) { } s2 = input.substring(s2, peg$currPos); if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c9; + s3 = peg$c8; peg$currPos++; } else { s3 = peg$FAILED; @@ -1871,7 +1907,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s1 = peg$c10; + s1 = peg$c9; peg$currPos++; } else { s1 = peg$FAILED; @@ -1883,7 +1919,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s5 = peg$c11; + s5 = peg$c10; peg$currPos++; } else { s5 = peg$FAILED; @@ -1911,38 +1947,24 @@ function peg$parse(input, options) { } function peg$parseTypeName() { - var s0, s1, s2; + var s0, s1; s0 = peg$currPos; - s1 = peg$parseidentifier(); + s1 = peg$parseQualifiedIdent(); if (s1 !== peg$FAILED) { - peg$savedPos = peg$currPos; - s2 = peg$f12(s1); - if (s2) { - s2 = undefined; - } else { - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f13(s1); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + s0 = s1; } else { peg$currPos = s0; s0 = peg$FAILED; } if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = peg$parseQualifiedIdent(); + s1 = peg$parseidentifier(); if (s1 !== peg$FAILED) { - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; + peg$savedPos = s0; + s1 = peg$f12(s1); } + s0 = s1; } return s0; @@ -1982,7 +2004,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c12; + s1 = peg$c11; peg$currPos++; } else { s1 = peg$FAILED; @@ -1994,7 +2016,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 93) { - s5 = peg$c13; + s5 = peg$c12; peg$currPos++; } else { s5 = peg$FAILED; @@ -2004,7 +2026,7 @@ function peg$parse(input, options) { s6 = peg$parseType(); if (s6 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f14(s3, s6); + s0 = peg$f13(s3, s6); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2030,7 +2052,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c12; + s1 = peg$c11; peg$currPos++; } else { s1 = peg$FAILED; @@ -2038,7 +2060,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 93) { - s2 = peg$c13; + s2 = peg$c12; peg$currPos++; } else { s2 = peg$FAILED; @@ -2048,7 +2070,7 @@ function peg$parse(input, options) { s3 = peg$parseType(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f15(s3); + s0 = peg$f14(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2066,11 +2088,11 @@ function peg$parse(input, options) { } function peg$parseStructType() { - var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c14) { - s1 = peg$c14; + if (input.substr(peg$currPos, 6) === peg$c13) { + s1 = peg$c13; peg$currPos += 6; } else { s1 = peg$FAILED; @@ -2079,7 +2101,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 123) { - s3 = peg$c15; + s3 = peg$c14; peg$currPos++; } else { s3 = peg$FAILED; @@ -2094,7 +2116,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -2103,8 +2125,8 @@ function peg$parse(input, options) { if (s10 === peg$FAILED) { s10 = null; } - s7 = [s7, s8, s9, s10]; - s6 = s7; + s11 = peg$parse_(); + s6 = s8; } else { peg$currPos = s6; s6 = peg$FAILED; @@ -2117,7 +2139,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -2126,24 +2148,23 @@ function peg$parse(input, options) { if (s10 === peg$FAILED) { s10 = null; } - s7 = [s7, s8, s9, s10]; - s6 = s7; + s11 = peg$parse_(); + s6 = s8; } else { peg$currPos = s6; s6 = peg$FAILED; } } - s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 125) { - s7 = peg$c17; + s6 = peg$c16; peg$currPos++; } else { - s7 = peg$FAILED; + s6 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e30); } } - if (s7 !== peg$FAILED) { - s1 = [s1, s2, s3, s4, s5, s6, s7]; - s0 = s1; + if (s6 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f15(s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2161,34 +2182,28 @@ function peg$parse(input, options) { } function peg$parseFieldDecl() { - var s0, s1, s2, s3; + var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - s1 = peg$currPos; - s2 = peg$parseIdentifierList(); - if (s2 !== peg$FAILED) { + s1 = peg$parseIdentifierList(); + if (s1 !== peg$FAILED) { + s2 = peg$parse_(); s3 = peg$parseType(); + if (s3 === peg$FAILED) { + s3 = peg$parseEmbeddedField(); + } if (s3 !== peg$FAILED) { - s2 = [s2, s3]; - s1 = s2; + s4 = peg$parse_(); + s5 = peg$parsestring_lit(); + if (s5 === peg$FAILED) { + s5 = null; + } + peg$savedPos = s0; + s0 = peg$f16(s1, s3); } else { - peg$currPos = s1; - s1 = peg$FAILED; - } - } else { - peg$currPos = s1; - s1 = peg$FAILED; - } - if (s1 === peg$FAILED) { - s1 = peg$parseEmbeddedField(); - } - if (s1 !== peg$FAILED) { - s2 = peg$parsestring_lit(); - if (s2 === peg$FAILED) { - s2 = null; + peg$currPos = s0; + s0 = peg$FAILED; } - s1 = [s1, s2]; - s0 = s1; } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2202,7 +2217,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 42) { - s1 = peg$c18; + s1 = peg$c17; peg$currPos++; } else { s1 = peg$FAILED; @@ -2228,7 +2243,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 42) { - s1 = peg$c18; + s1 = peg$c17; peg$currPos++; } else { s1 = peg$FAILED; @@ -2255,8 +2270,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c19) { - s1 = peg$c19; + if (input.substr(peg$currPos, 4) === peg$c18) { + s1 = peg$c18; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -2291,7 +2306,7 @@ function peg$parse(input, options) { s3 = null; } peg$savedPos = s0; - s0 = peg$f16(s1, s3); + s0 = peg$f17(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2316,7 +2331,7 @@ function peg$parse(input, options) { s1 = peg$parseType(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f17(s1); + s1 = peg$f18(s1); } s0 = s1; } @@ -2329,7 +2344,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s1 = peg$c10; + s1 = peg$c9; peg$currPos++; } else { s1 = peg$FAILED; @@ -2343,7 +2358,7 @@ function peg$parse(input, options) { } s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -2354,7 +2369,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s7 = peg$c11; + s7 = peg$c10; peg$currPos++; } else { s7 = peg$FAILED; @@ -2362,7 +2377,7 @@ function peg$parse(input, options) { } if (s7 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f18(s3); + s0 = peg$f19(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2385,7 +2400,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -2409,7 +2424,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -2430,7 +2445,7 @@ function peg$parse(input, options) { } } peg$savedPos = s0; - s0 = peg$f19(s1, s2); + s0 = peg$f20(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2451,7 +2466,7 @@ function peg$parse(input, options) { s3 = peg$parseType(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f20(s1, s3); + s0 = peg$f21(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2461,7 +2476,7 @@ function peg$parse(input, options) { s1 = peg$parseType(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f21(s1); + s1 = peg$f22(s1); } s0 = s1; } @@ -2473,8 +2488,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; s0 = peg$currPos; - if (input.substr(peg$currPos, 9) === peg$c21) { - s1 = peg$c21; + if (input.substr(peg$currPos, 9) === peg$c20) { + s1 = peg$c20; peg$currPos += 9; } else { s1 = peg$FAILED; @@ -2483,7 +2498,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 123) { - s3 = peg$c15; + s3 = peg$c14; peg$currPos++; } else { s3 = peg$FAILED; @@ -2498,7 +2513,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -2521,7 +2536,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -2539,7 +2554,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 125) { - s7 = peg$c17; + s7 = peg$c16; peg$currPos++; } else { s7 = peg$FAILED; @@ -2608,7 +2623,7 @@ function peg$parse(input, options) { s3 = []; s4 = peg$currPos; if (input.charCodeAt(peg$currPos) === 124) { - s5 = peg$c22; + s5 = peg$c21; peg$currPos++; } else { s5 = peg$FAILED; @@ -2633,7 +2648,7 @@ function peg$parse(input, options) { s3.push(s4); s4 = peg$currPos; if (input.charCodeAt(peg$currPos) === 124) { - s5 = peg$c22; + s5 = peg$c21; peg$currPos++; } else { s5 = peg$FAILED; @@ -2681,7 +2696,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 126) { - s1 = peg$c23; + s1 = peg$c22; peg$currPos++; } else { s1 = peg$FAILED; @@ -2708,8 +2723,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c24) { - s1 = peg$c24; + if (input.substr(peg$currPos, 3) === peg$c23) { + s1 = peg$c23; peg$currPos += 3; } else { s1 = peg$FAILED; @@ -2718,7 +2733,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 91) { - s3 = peg$c12; + s3 = peg$c11; peg$currPos++; } else { s3 = peg$FAILED; @@ -2730,7 +2745,7 @@ function peg$parse(input, options) { if (s5 !== peg$FAILED) { s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 93) { - s7 = peg$c13; + s7 = peg$c12; peg$currPos++; } else { s7 = peg$FAILED; @@ -2741,7 +2756,7 @@ function peg$parse(input, options) { s9 = peg$parseType(); if (s9 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f22(s5, s9); + s0 = peg$f23(s5, s9); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2770,8 +2785,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c25) { - s1 = peg$c25; + if (input.substr(peg$currPos, 4) === peg$c24) { + s1 = peg$c24; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -2779,8 +2794,8 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c26) { - s3 = peg$c26; + if (input.substr(peg$currPos, 2) === peg$c25) { + s3 = peg$c25; peg$currPos += 2; } else { s3 = peg$FAILED; @@ -2791,7 +2806,7 @@ function peg$parse(input, options) { s5 = peg$parseType(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f23(s5); + s0 = peg$f24(s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2806,8 +2821,8 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c26) { - s1 = peg$c26; + if (input.substr(peg$currPos, 2) === peg$c25) { + s1 = peg$c25; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -2815,8 +2830,8 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c25) { - s3 = peg$c25; + if (input.substr(peg$currPos, 4) === peg$c24) { + s3 = peg$c24; peg$currPos += 4; } else { s3 = peg$FAILED; @@ -2827,7 +2842,7 @@ function peg$parse(input, options) { s5 = peg$parseType(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f24(s5); + s0 = peg$f25(s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2842,8 +2857,8 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c25) { - s1 = peg$c25; + if (input.substr(peg$currPos, 4) === peg$c24) { + s1 = peg$c24; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -2854,7 +2869,7 @@ function peg$parse(input, options) { s3 = peg$parseType(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f25(s3); + s0 = peg$f26(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2874,7 +2889,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 123) { - s1 = peg$c15; + s1 = peg$c14; peg$currPos++; } else { s1 = peg$FAILED; @@ -2885,7 +2900,7 @@ function peg$parse(input, options) { s3 = peg$parseStatementList(); s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 125) { - s5 = peg$c17; + s5 = peg$c16; peg$currPos++; } else { s5 = peg$FAILED; @@ -2893,7 +2908,7 @@ function peg$parse(input, options) { } if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f26(s3); + s0 = peg$f27(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2916,7 +2931,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s5 = peg$c16; + s5 = peg$c15; peg$currPos++; } else { s5 = peg$FAILED; @@ -2938,7 +2953,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s5 = peg$c16; + s5 = peg$c15; peg$currPos++; } else { s5 = peg$FAILED; @@ -2989,8 +3004,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c27) { - s1 = peg$c27; + if (input.substr(peg$currPos, 5) === peg$c26) { + s1 = peg$c26; peg$currPos += 5; } else { s1 = peg$FAILED; @@ -3027,7 +3042,7 @@ function peg$parse(input, options) { } s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s6 = peg$c28; + s6 = peg$c27; peg$currPos++; } else { s6 = peg$FAILED; @@ -3038,7 +3053,7 @@ function peg$parse(input, options) { s8 = peg$parseExpressionList(); if (s8 !== peg$FAILED) { peg$savedPos = s3; - s3 = peg$f27(s1, s4, s8); + s3 = peg$f28(s1, s4, s8); } else { peg$currPos = s3; s3 = peg$FAILED; @@ -3049,7 +3064,7 @@ function peg$parse(input, options) { } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f28(s1, s3); + s0 = peg$f29(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3072,7 +3087,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3097,7 +3112,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3119,7 +3134,7 @@ function peg$parse(input, options) { } } peg$savedPos = s0; - s0 = peg$f29(s1, s2); + s0 = peg$f30(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3138,7 +3153,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3163,7 +3178,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3185,7 +3200,7 @@ function peg$parse(input, options) { } } peg$savedPos = s0; - s0 = peg$f30(s1, s2); + s0 = peg$f31(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3198,8 +3213,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c29) { - s1 = peg$c29; + if (input.substr(peg$currPos, 4) === peg$c28) { + s1 = peg$c28; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -3211,7 +3226,7 @@ function peg$parse(input, options) { if (s3 === peg$FAILED) { s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s4 = peg$c10; + s4 = peg$c9; peg$currPos++; } else { s4 = peg$FAILED; @@ -3226,7 +3241,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -3249,7 +3264,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -3267,7 +3282,7 @@ function peg$parse(input, options) { } s7 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s8 = peg$c11; + s8 = peg$c10; peg$currPos++; } else { s8 = peg$FAILED; @@ -3286,8 +3301,7 @@ function peg$parse(input, options) { } } if (s3 !== peg$FAILED) { - s1 = [s1, s2, s3]; - s0 = s1; + s0 = s3; } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3319,7 +3333,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s3 = peg$c28; + s3 = peg$c27; peg$currPos++; } else { s3 = peg$FAILED; @@ -3361,8 +3375,8 @@ function peg$parse(input, options) { s4 = peg$parse_(); s5 = peg$parseType(); if (s5 !== peg$FAILED) { - s1 = [s1, s2, s3, s4, s5]; - s0 = s1; + peg$savedPos = s0; + s0 = peg$f32(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3380,7 +3394,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c12; + s1 = peg$c11; peg$currPos++; } else { s1 = peg$FAILED; @@ -3392,7 +3406,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3403,7 +3417,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 93) { - s7 = peg$c13; + s7 = peg$c12; peg$currPos++; } else { s7 = peg$FAILED; @@ -3438,7 +3452,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3463,7 +3477,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -3521,8 +3535,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c30) { - s1 = peg$c30; + if (input.substr(peg$currPos, 3) === peg$c29) { + s1 = peg$c29; peg$currPos += 3; } else { s1 = peg$FAILED; @@ -3558,7 +3572,7 @@ function peg$parse(input, options) { s5 = peg$currPos; s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s7 = peg$c28; + s7 = peg$c27; peg$currPos++; } else { s7 = peg$FAILED; @@ -3581,7 +3595,7 @@ function peg$parse(input, options) { s5 = null; } peg$savedPos = s3; - s3 = peg$f31(s1, s4, s5); + s3 = peg$f33(s1, s4, s5); } else { peg$currPos = s3; s3 = peg$FAILED; @@ -3590,7 +3604,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s5 = peg$c28; + s5 = peg$c27; peg$currPos++; } else { s5 = peg$FAILED; @@ -3601,7 +3615,7 @@ function peg$parse(input, options) { s7 = peg$parseExpressionList(); if (s7 !== peg$FAILED) { peg$savedPos = s3; - s3 = peg$f32(s1, s7); + s3 = peg$f34(s1, s7); } else { peg$currPos = s3; s3 = peg$FAILED; @@ -3613,7 +3627,7 @@ function peg$parse(input, options) { } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f33(s1, s3); + s0 = peg$f35(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3633,8 +3647,8 @@ function peg$parse(input, options) { s1 = peg$parseIdentifierList(); if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c31) { - s3 = peg$c31; + if (input.substr(peg$currPos, 2) === peg$c30) { + s3 = peg$c30; peg$currPos += 2; } else { s3 = peg$FAILED; @@ -3643,9 +3657,12 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); s5 = peg$parseExpressionList(); + if (s5 === peg$FAILED) { + s5 = peg$parseStructType(); + } if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f34(s1, s5); + s0 = peg$f36(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3666,8 +3683,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c19) { - s1 = peg$c19; + if (input.substr(peg$currPos, 4) === peg$c18) { + s1 = peg$c18; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -3686,7 +3703,7 @@ function peg$parse(input, options) { s7 = null; } peg$savedPos = s0; - s0 = peg$f35(s3, s5, s7); + s0 = peg$f37(s3, s5, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3707,8 +3724,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c19) { - s1 = peg$c19; + if (input.substr(peg$currPos, 4) === peg$c18) { + s1 = peg$c18; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -3760,7 +3777,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s1 = peg$c10; + s1 = peg$c9; peg$currPos++; } else { s1 = peg$FAILED; @@ -3772,7 +3789,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s5 = peg$c11; + s5 = peg$c10; peg$currPos++; } else { s5 = peg$FAILED; @@ -3844,7 +3861,7 @@ function peg$parse(input, options) { s1 = peg$parseidentifier(); if (s1 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 46) { - s2 = peg$c7; + s2 = peg$c6; peg$currPos++; } else { s2 = peg$FAILED; @@ -3854,7 +3871,7 @@ function peg$parse(input, options) { s3 = peg$parseidentifier(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f36(s1, s3); + s0 = peg$f38(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3881,7 +3898,7 @@ function peg$parse(input, options) { s3 = peg$parseLiteralValue(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f37(s1, s3); + s0 = peg$f39(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3898,7 +3915,7 @@ function peg$parse(input, options) { s3 = peg$parseLiteralValue(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f38(s1, s3); + s0 = peg$f40(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3917,7 +3934,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 123) { - s1 = peg$c15; + s1 = peg$c14; peg$currPos++; } else { s1 = peg$FAILED; @@ -3930,7 +3947,7 @@ function peg$parse(input, options) { if (s4 !== peg$FAILED) { s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s6 = peg$c20; + s6 = peg$c19; peg$currPos++; } else { s6 = peg$FAILED; @@ -3949,7 +3966,7 @@ function peg$parse(input, options) { s3 = null; } if (input.charCodeAt(peg$currPos) === 125) { - s4 = peg$c17; + s4 = peg$c16; peg$currPos++; } else { s4 = peg$FAILED; @@ -3957,7 +3974,7 @@ function peg$parse(input, options) { } if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f39(s3); + s0 = peg$f41(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -3980,7 +3997,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -4004,7 +4021,7 @@ function peg$parse(input, options) { s3 = peg$currPos; s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -4025,7 +4042,7 @@ function peg$parse(input, options) { } } peg$savedPos = s0; - s0 = peg$f40(s1, s2); + s0 = peg$f42(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4049,8 +4066,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c19) { - s1 = peg$c19; + if (input.substr(peg$currPos, 4) === peg$c18) { + s1 = peg$c18; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -4064,7 +4081,7 @@ function peg$parse(input, options) { s5 = peg$parseBlock(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f41(s3, s5); + s0 = peg$f43(s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4112,7 +4129,7 @@ function peg$parse(input, options) { s4 = peg$parsePrimaryExprModifier(); } peg$savedPos = s0; - s0 = peg$f42(s1, s3); + s0 = peg$f44(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4146,7 +4163,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s1 = peg$c7; + s1 = peg$c6; peg$currPos++; } else { s1 = peg$FAILED; @@ -4156,7 +4173,7 @@ function peg$parse(input, options) { s2 = peg$parseidentifier(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f43(s2); + s0 = peg$f45(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4174,7 +4191,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c12; + s1 = peg$c11; peg$currPos++; } else { s1 = peg$FAILED; @@ -4187,7 +4204,7 @@ function peg$parse(input, options) { s4 = peg$currPos; s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s6 = peg$c20; + s6 = peg$c19; peg$currPos++; } else { s6 = peg$FAILED; @@ -4205,7 +4222,7 @@ function peg$parse(input, options) { } s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 93) { - s6 = peg$c13; + s6 = peg$c12; peg$currPos++; } else { s6 = peg$FAILED; @@ -4213,7 +4230,7 @@ function peg$parse(input, options) { } if (s6 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f44(s3); + s0 = peg$f46(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4235,7 +4252,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c12; + s1 = peg$c11; peg$currPos++; } else { s1 = peg$FAILED; @@ -4249,7 +4266,7 @@ function peg$parse(input, options) { } s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 58) { - s5 = peg$c32; + s5 = peg$c31; peg$currPos++; } else { s5 = peg$FAILED; @@ -4263,7 +4280,7 @@ function peg$parse(input, options) { } s8 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 93) { - s9 = peg$c13; + s9 = peg$c12; peg$currPos++; } else { s9 = peg$FAILED; @@ -4271,7 +4288,7 @@ function peg$parse(input, options) { } if (s9 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f45(s3, s7); + s0 = peg$f47(s3, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4293,7 +4310,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s1 = peg$c7; + s1 = peg$c6; peg$currPos++; } else { s1 = peg$FAILED; @@ -4302,7 +4319,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 40) { - s3 = peg$c10; + s3 = peg$c9; peg$currPos++; } else { s3 = peg$FAILED; @@ -4314,7 +4331,7 @@ function peg$parse(input, options) { if (s5 !== peg$FAILED) { s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s7 = peg$c11; + s7 = peg$c10; peg$currPos++; } else { s7 = peg$FAILED; @@ -4348,7 +4365,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s1 = peg$c10; + s1 = peg$c9; peg$currPos++; } else { s1 = peg$FAILED; @@ -4362,7 +4379,7 @@ function peg$parse(input, options) { } s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s5 = peg$c20; + s5 = peg$c19; peg$currPos++; } else { s5 = peg$FAILED; @@ -4373,7 +4390,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s7 = peg$c11; + s7 = peg$c10; peg$currPos++; } else { s7 = peg$FAILED; @@ -4381,7 +4398,7 @@ function peg$parse(input, options) { } if (s7 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f46(s3); + s0 = peg$f48(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4401,7 +4418,7 @@ function peg$parse(input, options) { s1 = peg$currPos; s2 = []; s3 = input.charAt(peg$currPos); - if (peg$r12.test(s3)) { + if (peg$r13.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; @@ -4411,7 +4428,7 @@ function peg$parse(input, options) { while (s3 !== peg$FAILED) { s2.push(s3); s3 = input.charAt(peg$currPos); - if (peg$r12.test(s3)) { + if (peg$r13.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; @@ -4429,7 +4446,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 40) { - s3 = peg$c10; + s3 = peg$c9; peg$currPos++; } else { s3 = peg$FAILED; @@ -4442,7 +4459,7 @@ function peg$parse(input, options) { s6 = peg$parse_(); s7 = peg$currPos; if (input.charCodeAt(peg$currPos) === 44) { - s8 = peg$c20; + s8 = peg$c19; peg$currPos++; } else { s8 = peg$FAILED; @@ -4466,7 +4483,7 @@ function peg$parse(input, options) { } s8 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s9 = peg$c11; + s9 = peg$c10; peg$currPos++; } else { s9 = peg$FAILED; @@ -4474,7 +4491,7 @@ function peg$parse(input, options) { } if (s9 !== peg$FAILED) { peg$savedPos = peg$currPos; - s10 = peg$f47(s1, s5, s7); + s10 = peg$f49(s1, s5, s7); if (s10) { s10 = undefined; } else { @@ -4482,7 +4499,7 @@ function peg$parse(input, options) { } if (s10 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f48(s1, s5, s7); + s0 = peg$f50(s1, s5, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4508,7 +4525,7 @@ function peg$parse(input, options) { s1 = peg$currPos; s2 = []; s3 = input.charAt(peg$currPos); - if (peg$r12.test(s3)) { + if (peg$r13.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; @@ -4518,7 +4535,7 @@ function peg$parse(input, options) { while (s3 !== peg$FAILED) { s2.push(s3); s3 = input.charAt(peg$currPos); - if (peg$r12.test(s3)) { + if (peg$r13.test(s3)) { peg$currPos++; } else { s3 = peg$FAILED; @@ -4536,7 +4553,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 40) { - s3 = peg$c10; + s3 = peg$c9; peg$currPos++; } else { s3 = peg$FAILED; @@ -4550,7 +4567,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s7 = peg$c11; + s7 = peg$c10; peg$currPos++; } else { s7 = peg$FAILED; @@ -4558,7 +4575,7 @@ function peg$parse(input, options) { } if (s7 !== peg$FAILED) { peg$savedPos = peg$currPos; - s8 = peg$f49(s1, s5); + s8 = peg$f51(s1, s5); if (s8) { s8 = undefined; } else { @@ -4566,7 +4583,7 @@ function peg$parse(input, options) { } if (s8 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f50(s1, s5); + s0 = peg$f52(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4595,7 +4612,7 @@ function peg$parse(input, options) { s1 = peg$parseType(); if (s1 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 46) { - s2 = peg$c7; + s2 = peg$c6; peg$currPos++; } else { s2 = peg$FAILED; @@ -4667,7 +4684,7 @@ function peg$parse(input, options) { s2 = peg$parseConjExpr(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f51(s1, s2); + s0 = peg$f53(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4724,7 +4741,7 @@ function peg$parse(input, options) { s2 = peg$parseRelExpr(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f52(s1, s2); + s0 = peg$f54(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4781,7 +4798,7 @@ function peg$parse(input, options) { s2 = peg$parseAddExpr(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f53(s1, s2); + s0 = peg$f55(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4838,7 +4855,7 @@ function peg$parse(input, options) { s2 = peg$parseMulExpr(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f54(s1, s2); + s0 = peg$f56(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4895,7 +4912,7 @@ function peg$parse(input, options) { s2 = peg$parseUnaryExpr(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f55(s1, s2); + s0 = peg$f57(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4919,7 +4936,7 @@ function peg$parse(input, options) { s3 = peg$parseUnaryExpr(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f56(s1, s3); + s0 = peg$f58(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -4937,8 +4954,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c33) { - s1 = peg$c33; + if (input.substr(peg$currPos, 2) === peg$c32) { + s1 = peg$c32; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -4946,13 +4963,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f57(); + s1 = peg$f59(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c34) { - s1 = peg$c34; + if (input.substr(peg$currPos, 2) === peg$c33) { + s1 = peg$c33; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -4960,13 +4977,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f58(); + s1 = peg$f60(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c35) { - s1 = peg$c35; + if (input.substr(peg$currPos, 2) === peg$c34) { + s1 = peg$c34; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -4974,13 +4991,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f59(); + s1 = peg$f61(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c36) { - s1 = peg$c36; + if (input.substr(peg$currPos, 2) === peg$c35) { + s1 = peg$c35; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -4988,13 +5005,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f60(); + s1 = peg$f62(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c37; + s1 = peg$c36; peg$currPos++; } else { s1 = peg$FAILED; @@ -5004,7 +5021,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 45) { - s3 = peg$c38; + s3 = peg$c37; peg$currPos++; } else { s3 = peg$FAILED; @@ -5019,7 +5036,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f61(); + s0 = peg$f63(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5031,7 +5048,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c39; + s1 = peg$c38; peg$currPos++; } else { s1 = peg$FAILED; @@ -5039,7 +5056,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f62(); + s1 = peg$f64(); } s0 = s1; } @@ -5056,7 +5073,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 43) { - s1 = peg$c40; + s1 = peg$c39; peg$currPos++; } else { s1 = peg$FAILED; @@ -5066,7 +5083,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 43) { - s3 = peg$c40; + s3 = peg$c39; peg$currPos++; } else { s3 = peg$FAILED; @@ -5081,7 +5098,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f63(); + s0 = peg$f65(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5093,7 +5110,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 45) { - s1 = peg$c38; + s1 = peg$c37; peg$currPos++; } else { s1 = peg$FAILED; @@ -5103,7 +5120,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 45) { - s3 = peg$c38; + s3 = peg$c37; peg$currPos++; } else { s3 = peg$FAILED; @@ -5118,7 +5135,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f64(); + s0 = peg$f66(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5130,7 +5147,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 124) { - s1 = peg$c22; + s1 = peg$c21; peg$currPos++; } else { s1 = peg$FAILED; @@ -5140,7 +5157,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 124) { - s3 = peg$c22; + s3 = peg$c21; peg$currPos++; } else { s3 = peg$FAILED; @@ -5155,7 +5172,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f65(); + s0 = peg$f67(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5167,7 +5184,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 94) { - s1 = peg$c41; + s1 = peg$c40; peg$currPos++; } else { s1 = peg$FAILED; @@ -5177,7 +5194,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 94) { - s3 = peg$c41; + s3 = peg$c40; peg$currPos++; } else { s3 = peg$FAILED; @@ -5192,7 +5209,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f66(); + s0 = peg$f68(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5213,7 +5230,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 42) { - s1 = peg$c18; + s1 = peg$c17; peg$currPos++; } else { s1 = peg$FAILED; @@ -5223,7 +5240,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 42) { - s3 = peg$c18; + s3 = peg$c17; peg$currPos++; } else { s3 = peg$FAILED; @@ -5238,7 +5255,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f67(); + s0 = peg$f69(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5250,7 +5267,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 47) { - s1 = peg$c42; + s1 = peg$c41; peg$currPos++; } else { s1 = peg$FAILED; @@ -5260,7 +5277,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 47) { - s3 = peg$c42; + s3 = peg$c41; peg$currPos++; } else { s3 = peg$FAILED; @@ -5275,7 +5292,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f68(); + s0 = peg$f70(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5287,7 +5304,7 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 37) { - s1 = peg$c43; + s1 = peg$c42; peg$currPos++; } else { s1 = peg$FAILED; @@ -5295,13 +5312,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f69(); + s1 = peg$f71(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c44) { - s1 = peg$c44; + if (input.substr(peg$currPos, 2) === peg$c43) { + s1 = peg$c43; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5309,13 +5326,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f70(); + s1 = peg$f72(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c45) { - s1 = peg$c45; + if (input.substr(peg$currPos, 2) === peg$c44) { + s1 = peg$c44; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5323,13 +5340,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f71(); + s1 = peg$f73(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 38) { - s1 = peg$c46; + s1 = peg$c45; peg$currPos++; } else { s1 = peg$FAILED; @@ -5339,7 +5356,7 @@ function peg$parse(input, options) { s2 = peg$currPos; peg$silentFails++; if (input.charCodeAt(peg$currPos) === 38) { - s3 = peg$c46; + s3 = peg$c45; peg$currPos++; } else { s3 = peg$FAILED; @@ -5354,7 +5371,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f72(); + s0 = peg$f74(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5365,8 +5382,8 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c47) { - s1 = peg$c47; + if (input.substr(peg$currPos, 2) === peg$c46) { + s1 = peg$c46; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5374,7 +5391,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f73(); + s1 = peg$f75(); } s0 = s1; } @@ -5391,8 +5408,8 @@ function peg$parse(input, options) { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c48) { - s1 = peg$c48; + if (input.substr(peg$currPos, 2) === peg$c47) { + s1 = peg$c47; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5400,7 +5417,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f74(); + s1 = peg$f76(); } s0 = s1; @@ -5411,8 +5428,8 @@ function peg$parse(input, options) { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c49) { - s1 = peg$c49; + if (input.substr(peg$currPos, 2) === peg$c48) { + s1 = peg$c48; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5420,7 +5437,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f75(); + s1 = peg$f77(); } s0 = s1; @@ -5432,7 +5449,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 43) { - s1 = peg$c40; + s1 = peg$c39; peg$currPos++; } else { s1 = peg$FAILED; @@ -5440,13 +5457,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f76(); + s1 = peg$f78(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 45) { - s1 = peg$c38; + s1 = peg$c37; peg$currPos++; } else { s1 = peg$FAILED; @@ -5454,13 +5471,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f77(); + s1 = peg$f79(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 33) { - s1 = peg$c50; + s1 = peg$c49; peg$currPos++; } else { s1 = peg$FAILED; @@ -5468,13 +5485,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f78(); + s1 = peg$f80(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 94) { - s1 = peg$c41; + s1 = peg$c40; peg$currPos++; } else { s1 = peg$FAILED; @@ -5482,13 +5499,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f79(); + s1 = peg$f81(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 42) { - s1 = peg$c18; + s1 = peg$c17; peg$currPos++; } else { s1 = peg$FAILED; @@ -5496,13 +5513,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f80(); + s1 = peg$f82(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 38) { - s1 = peg$c46; + s1 = peg$c45; peg$currPos++; } else { s1 = peg$FAILED; @@ -5510,13 +5527,13 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f81(); + s1 = peg$f83(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c26) { - s1 = peg$c26; + if (input.substr(peg$currPos, 2) === peg$c25) { + s1 = peg$c25; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5524,7 +5541,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f82(); + s1 = peg$f84(); } s0 = s1; } @@ -5545,7 +5562,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 40) { - s3 = peg$c10; + s3 = peg$c9; peg$currPos++; } else { s3 = peg$FAILED; @@ -5557,7 +5574,7 @@ function peg$parse(input, options) { if (s5 !== peg$FAILED) { s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s7 = peg$c11; + s7 = peg$c10; peg$currPos++; } else { s7 = peg$FAILED; @@ -5566,7 +5583,7 @@ function peg$parse(input, options) { if (s7 !== peg$FAILED) { s8 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 44) { - s9 = peg$c20; + s9 = peg$c19; peg$currPos++; } else { s9 = peg$FAILED; @@ -5577,7 +5594,7 @@ function peg$parse(input, options) { } s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s11 = peg$c11; + s11 = peg$c10; peg$currPos++; } else { s11 = peg$FAILED; @@ -5688,7 +5705,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 58) { - s3 = peg$c32; + s3 = peg$c31; peg$currPos++; } else { s3 = peg$FAILED; @@ -5723,8 +5740,8 @@ function peg$parse(input, options) { s1 = peg$parseidentifier(); if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c26) { - s3 = peg$c26; + if (input.substr(peg$currPos, 2) === peg$c25) { + s3 = peg$c25; peg$currPos += 2; } else { s3 = peg$FAILED; @@ -5735,7 +5752,7 @@ function peg$parse(input, options) { s5 = peg$parseExpression(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f83(s1, s5); + s0 = peg$f85(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5759,16 +5776,16 @@ function peg$parse(input, options) { s1 = peg$parseExpression(); if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c51) { - s3 = peg$c51; + if (input.substr(peg$currPos, 2) === peg$c50) { + s3 = peg$c50; peg$currPos += 2; } else { s3 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e65); } } if (s3 === peg$FAILED) { - if (input.substr(peg$currPos, 2) === peg$c52) { - s3 = peg$c52; + if (input.substr(peg$currPos, 2) === peg$c51) { + s3 = peg$c51; peg$currPos += 2; } else { s3 = peg$FAILED; @@ -5777,7 +5794,7 @@ function peg$parse(input, options) { } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f84(s1, s3); + s0 = peg$f86(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5809,7 +5826,7 @@ function peg$parse(input, options) { s5 = peg$parseExpressionList(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f85(s1, s3, s5); + s0 = peg$f87(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5831,7 +5848,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = input.charAt(peg$currPos); - if (peg$r13.test(s1)) { + if (peg$r14.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; @@ -5841,7 +5858,7 @@ function peg$parse(input, options) { s1 = null; } if (input.charCodeAt(peg$currPos) === 61) { - s2 = peg$c28; + s2 = peg$c27; peg$currPos++; } else { s2 = peg$FAILED; @@ -5862,8 +5879,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c53) { - s1 = peg$c53; + if (input.substr(peg$currPos, 2) === peg$c52) { + s1 = peg$c52; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -5876,7 +5893,7 @@ function peg$parse(input, options) { if (s4 !== peg$FAILED) { s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s6 = peg$c16; + s6 = peg$c15; peg$currPos++; } else { s6 = peg$FAILED; @@ -5903,8 +5920,8 @@ function peg$parse(input, options) { if (s7 !== peg$FAILED) { s8 = peg$parse_(); s9 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c54) { - s10 = peg$c54; + if (input.substr(peg$currPos, 4) === peg$c53) { + s10 = peg$c53; peg$currPos += 4; } else { s10 = peg$FAILED; @@ -5930,7 +5947,7 @@ function peg$parse(input, options) { s9 = null; } peg$savedPos = s0; - s0 = peg$f86(s3, s5, s7, s9); + s0 = peg$f88(s3, s5, s7, s9); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -5951,8 +5968,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c55) { - s1 = peg$c55; + if (input.substr(peg$currPos, 6) === peg$c54) { + s1 = peg$c54; peg$currPos += 6; } else { s1 = peg$FAILED; @@ -5965,7 +5982,7 @@ function peg$parse(input, options) { if (s4 !== peg$FAILED) { s5 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s6 = peg$c16; + s6 = peg$c15; peg$currPos++; } else { s6 = peg$FAILED; @@ -5991,7 +6008,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 123) { - s7 = peg$c15; + s7 = peg$c14; peg$currPos++; } else { s7 = peg$FAILED; @@ -6024,7 +6041,7 @@ function peg$parse(input, options) { } } if (input.charCodeAt(peg$currPos) === 125) { - s10 = peg$c17; + s10 = peg$c16; peg$currPos++; } else { s10 = peg$FAILED; @@ -6032,7 +6049,7 @@ function peg$parse(input, options) { } if (s10 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f87(s3, s5, s9); + s0 = peg$f89(s3, s5, s9); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6053,8 +6070,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c56) { - s1 = peg$c56; + if (input.substr(peg$currPos, 4) === peg$c55) { + s1 = peg$c55; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -6062,8 +6079,8 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 7) === peg$c57) { - s3 = peg$c57; + if (input.substr(peg$currPos, 7) === peg$c56) { + s3 = peg$c56; peg$currPos += 7; } else { s3 = peg$FAILED; @@ -6072,7 +6089,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 58) { - s5 = peg$c32; + s5 = peg$c31; peg$currPos++; } else { s5 = peg$FAILED; @@ -6083,7 +6100,7 @@ function peg$parse(input, options) { s7 = peg$parseStatementList(); if (s7 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f88(s7); + s0 = peg$f90(s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6102,8 +6119,8 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c56) { - s1 = peg$c56; + if (input.substr(peg$currPos, 4) === peg$c55) { + s1 = peg$c55; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -6115,7 +6132,7 @@ function peg$parse(input, options) { if (s3 !== peg$FAILED) { s4 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 58) { - s5 = peg$c32; + s5 = peg$c31; peg$currPos++; } else { s5 = peg$FAILED; @@ -6126,7 +6143,7 @@ function peg$parse(input, options) { s7 = peg$parseStatementList(); if (s7 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f89(s3, s7); + s0 = peg$f91(s3, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6152,8 +6169,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5; s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c58) { - s1 = peg$c58; + if (input.substr(peg$currPos, 3) === peg$c57) { + s1 = peg$c57; peg$currPos += 3; } else { s1 = peg$FAILED; @@ -6167,7 +6184,7 @@ function peg$parse(input, options) { s4 = peg$parseExpression(); if (s4 !== peg$FAILED) { peg$savedPos = s3; - s4 = peg$f90(s4); + s4 = peg$f92(s4); } s3 = s4; } @@ -6178,7 +6195,7 @@ function peg$parse(input, options) { s5 = peg$parseBlock(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f91(s3, s5); + s0 = peg$f93(s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6201,7 +6218,7 @@ function peg$parse(input, options) { } s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s3 = peg$c16; + s3 = peg$c15; peg$currPos++; } else { s3 = peg$FAILED; @@ -6215,7 +6232,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s7 = peg$c16; + s7 = peg$c15; peg$currPos++; } else { s7 = peg$FAILED; @@ -6228,7 +6245,7 @@ function peg$parse(input, options) { s9 = null; } peg$savedPos = s0; - s0 = peg$f92(s1, s5, s9); + s0 = peg$f94(s1, s5, s9); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6250,7 +6267,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s4 = peg$c28; + s4 = peg$c27; peg$currPos++; } else { s4 = peg$FAILED; @@ -6272,8 +6289,8 @@ function peg$parse(input, options) { s2 = peg$parseIdentifierList(); if (s2 !== peg$FAILED) { s3 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c31) { - s4 = peg$c31; + if (input.substr(peg$currPos, 2) === peg$c30) { + s4 = peg$c30; peg$currPos += 2; } else { s4 = peg$FAILED; @@ -6295,8 +6312,8 @@ function peg$parse(input, options) { s1 = null; } s2 = peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c59) { - s3 = peg$c59; + if (input.substr(peg$currPos, 5) === peg$c58) { + s3 = peg$c58; peg$currPos += 5; } else { s3 = peg$FAILED; @@ -6324,8 +6341,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c60) { - s1 = peg$c60; + if (input.substr(peg$currPos, 2) === peg$c59) { + s1 = peg$c59; peg$currPos += 2; } else { s1 = peg$FAILED; @@ -6336,7 +6353,7 @@ function peg$parse(input, options) { s3 = peg$parsePrimaryExpr(); if (s3 !== peg$FAILED) { peg$savedPos = peg$currPos; - s4 = peg$f93(s3); + s4 = peg$f95(s3); if (s4) { s4 = undefined; } else { @@ -6344,7 +6361,7 @@ function peg$parse(input, options) { } if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f94(s3); + s0 = peg$f96(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6365,8 +6382,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c61) { - s1 = peg$c61; + if (input.substr(peg$currPos, 6) === peg$c60) { + s1 = peg$c60; peg$currPos += 6; } else { s1 = peg$FAILED; @@ -6375,7 +6392,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 123) { - s3 = peg$c15; + s3 = peg$c14; peg$currPos++; } else { s3 = peg$FAILED; @@ -6409,7 +6426,7 @@ function peg$parse(input, options) { } s6 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 125) { - s7 = peg$c17; + s7 = peg$c16; peg$currPos++; } else { s7 = peg$FAILED; @@ -6417,7 +6434,7 @@ function peg$parse(input, options) { } if (s7 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f95(s5); + s0 = peg$f97(s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6442,7 +6459,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 58) { - s3 = peg$c32; + s3 = peg$c31; peg$currPos++; } else { s3 = peg$FAILED; @@ -6453,7 +6470,7 @@ function peg$parse(input, options) { s5 = peg$parseStatementList(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f96(s1, s5); + s0 = peg$f98(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6474,8 +6491,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c56) { - s1 = peg$c56; + if (input.substr(peg$currPos, 4) === peg$c55) { + s1 = peg$c55; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -6499,8 +6516,8 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 7) === peg$c57) { - s1 = peg$c57; + if (input.substr(peg$currPos, 7) === peg$c56) { + s1 = peg$c56; peg$currPos += 7; } else { s1 = peg$FAILED; @@ -6524,8 +6541,8 @@ function peg$parse(input, options) { s1 = peg$parseIdentifierList(); if (s1 !== peg$FAILED) { s2 = peg$parse_(); - if (input.substr(peg$currPos, 2) === peg$c31) { - s3 = peg$c31; + if (input.substr(peg$currPos, 2) === peg$c30) { + s3 = peg$c30; peg$currPos += 2; } else { s3 = peg$FAILED; @@ -6536,7 +6553,7 @@ function peg$parse(input, options) { s5 = peg$parseRecvExpr(); if (s5 !== peg$FAILED) { peg$savedPos = peg$currPos; - s6 = peg$f97(s1, s5); + s6 = peg$f99(s1, s5); if (s6) { s6 = undefined; } else { @@ -6544,7 +6561,7 @@ function peg$parse(input, options) { } if (s6 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f98(s1, s5); + s0 = peg$f100(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6568,7 +6585,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 61) { - s4 = peg$c28; + s4 = peg$c27; peg$currPos++; } else { s4 = peg$FAILED; @@ -6591,7 +6608,7 @@ function peg$parse(input, options) { s3 = peg$parseRecvExpr(); if (s3 !== peg$FAILED) { peg$savedPos = peg$currPos; - s4 = peg$f99(s1, s3); + s4 = peg$f101(s1, s3); if (s4) { s4 = undefined; } else { @@ -6599,7 +6616,7 @@ function peg$parse(input, options) { } if (s4 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f100(s1, s3); + s0 = peg$f102(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6620,7 +6637,7 @@ function peg$parse(input, options) { s1 = peg$parseExpression(); if (s1 !== peg$FAILED) { peg$savedPos = peg$currPos; - s2 = peg$f101(s1); + s2 = peg$f103(s1); if (s2) { s2 = undefined; } else { @@ -6628,7 +6645,7 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f102(s1); + s0 = peg$f104(s1); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6645,8 +6662,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c62) { - s1 = peg$c62; + if (input.substr(peg$currPos, 6) === peg$c61) { + s1 = peg$c61; peg$currPos += 6; } else { s1 = peg$FAILED; @@ -6659,7 +6676,7 @@ function peg$parse(input, options) { s3 = null; } peg$savedPos = s0; - s0 = peg$f103(s3); + s0 = peg$f105(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6672,8 +6689,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c63) { - s1 = peg$c63; + if (input.substr(peg$currPos, 5) === peg$c62) { + s1 = peg$c62; peg$currPos += 5; } else { s1 = peg$FAILED; @@ -6686,7 +6703,7 @@ function peg$parse(input, options) { s3 = null; } peg$savedPos = s0; - s0 = peg$f104(); + s0 = peg$f106(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6699,8 +6716,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 8) === peg$c64) { - s1 = peg$c64; + if (input.substr(peg$currPos, 8) === peg$c63) { + s1 = peg$c63; peg$currPos += 8; } else { s1 = peg$FAILED; @@ -6713,7 +6730,7 @@ function peg$parse(input, options) { s3 = null; } peg$savedPos = s0; - s0 = peg$f105(); + s0 = peg$f107(); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6726,8 +6743,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c65) { - s1 = peg$c65; + if (input.substr(peg$currPos, 4) === peg$c64) { + s1 = peg$c64; peg$currPos += 4; } else { s1 = peg$FAILED; @@ -6755,8 +6772,8 @@ function peg$parse(input, options) { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 11) === peg$c66) { - s1 = peg$c66; + if (input.substr(peg$currPos, 11) === peg$c65) { + s1 = peg$c65; peg$currPos += 11; } else { s1 = peg$FAILED; @@ -6764,7 +6781,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f106(); + s1 = peg$f108(); } s0 = s1; @@ -6775,8 +6792,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c67) { - s1 = peg$c67; + if (input.substr(peg$currPos, 5) === peg$c66) { + s1 = peg$c66; peg$currPos += 5; } else { s1 = peg$FAILED; @@ -6787,7 +6804,7 @@ function peg$parse(input, options) { s3 = peg$parseExpression(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f107(s3); + s0 = peg$f109(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6808,7 +6825,7 @@ function peg$parse(input, options) { if (s1 !== peg$FAILED) { s2 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s3 = peg$c16; + s3 = peg$c15; peg$currPos++; } else { s3 = peg$FAILED; @@ -6825,7 +6842,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -6848,7 +6865,7 @@ function peg$parse(input, options) { if (s8 !== peg$FAILED) { s9 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s10 = peg$c16; + s10 = peg$c15; peg$currPos++; } else { s10 = peg$FAILED; @@ -6871,7 +6888,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -6893,7 +6910,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -6909,7 +6926,7 @@ function peg$parse(input, options) { } } peg$savedPos = s0; - s0 = peg$f108(s1, s5, s6); + s0 = peg$f110(s1, s5, s6); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -6922,8 +6939,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 7) === peg$c68) { - s1 = peg$c68; + if (input.substr(peg$currPos, 7) === peg$c67) { + s1 = peg$c67; peg$currPos += 7; } else { s1 = peg$FAILED; @@ -6950,8 +6967,8 @@ function peg$parse(input, options) { var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c69) { - s1 = peg$c69; + if (input.substr(peg$currPos, 6) === peg$c68) { + s1 = peg$c68; peg$currPos += 6; } else { s1 = peg$FAILED; @@ -6963,7 +6980,7 @@ function peg$parse(input, options) { if (s3 === peg$FAILED) { s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 40) { - s4 = peg$c10; + s4 = peg$c9; peg$currPos++; } else { s4 = peg$FAILED; @@ -6978,7 +6995,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -7001,7 +7018,7 @@ function peg$parse(input, options) { if (s9 !== peg$FAILED) { s10 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 59) { - s11 = peg$c16; + s11 = peg$c15; peg$currPos++; } else { s11 = peg$FAILED; @@ -7019,7 +7036,7 @@ function peg$parse(input, options) { } s7 = peg$parse_(); if (input.charCodeAt(peg$currPos) === 41) { - s8 = peg$c11; + s8 = peg$c10; peg$currPos++; } else { s8 = peg$FAILED; @@ -7056,7 +7073,7 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s1 = peg$c7; + s1 = peg$c6; peg$currPos++; } else { s1 = peg$FAILED; @@ -7072,7 +7089,7 @@ function peg$parse(input, options) { s3 = peg$parsestring_lit(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f109(s1, s3); + s0 = peg$f111(s1, s3); } else { peg$currPos = s0; s0 = peg$FAILED; diff --git a/src/go-virtual-machine-main/virtual-machine/parser/golang_parser.ts b/src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/parser/golang_parser.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/golang_parser.ts diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/index.ts b/src/go-virtual-machine-main/virtual-machine/compiler/index.ts deleted file mode 100644 index 4a4296e..0000000 --- a/src/go-virtual-machine-main/virtual-machine/compiler/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Token, TokenLocation } from '../parser/tokens' - -import { TypeEnvironment } from './typing/type_environment' -import { CompileContext } from './environment' -import { DoneInstruction, Instruction } from './instructions' - -export class CompileError extends Error { - constructor(message: string, public sourceLocation: TokenLocation) { - super(message) - } -} - -export class Compiler { - instructions: Instruction[] = [] - symbols: (TokenLocation | null)[] = [] - context = new CompileContext() - type_environment = new TypeEnvironment() - - compile_program(token: Token) { - token.compile(this) - this.instructions.push(new DoneInstruction()) - } - - throwCompileError(message: string, sourceLocation: TokenLocation): never { - throw new CompileError(message, sourceLocation) - } -} - -const compile_tokens = (token: Token) => { - const compiler = new Compiler() - compiler.compile_program(token) - return { - instructions: compiler.instructions, - symbols: compiler.symbols, - } -} - -export { compile_tokens } diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/block.ts b/src/go-virtual-machine-main/virtual-machine/compiler/instructions/block.ts deleted file mode 100644 index 76c90ff..0000000 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/block.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Process } from '../../executor/process' -import { FrameNode } from '../../heap/types/environment' -import { Type } from '../typing' - -import { Instruction } from './base' - -export class BlockInstruction extends Instruction { - frame: Type[] = [] - identifiers: string[] = [] - constructor(public name: string, public for_block = false) { - super('BLOCK') - } - - set_frame(frame: Type[]) { - this.frame = [...frame] - } - - set_identifiers(identifiers: string[]) { - this.identifiers = [...identifiers] - } - - override toString(): string { - return super.toString() + ' ' + this.name - } - - override execute(process: Process): void { - const new_frame = FrameNode.create(this.frame.length, process.heap) - process.heap.temp_push(new_frame.addr) - for (let i = 0; i < this.frame.length; i++) { - const T = this.frame[i] - new_frame.set_idx(T.defaultNodeCreator()(process.heap), i) - } - const new_env = process.context - .E() - .extend_env(new_frame.addr, this.for_block).addr - process.context.pushRTS(new_env) - process.heap.temp_pop() - - if (process.debug_mode) { - process.debugger.env_alloc_map.set(new_env, process.runtime_count) - process.debugger.env_name_map.set(new_env, this.name) - const children = new_frame.get_children() - for (let i = 0; i < children.length; i++) { - process.debugger.identifier_map.set(children[i], this.identifiers[i]) - } - } - } -} -export class FuncBlockInstruction extends BlockInstruction { - constructor(public args: number) { - super('ANONY FUNC', false) - this.tag = 'FUNC_BLOCK' - } - - override toString(): string { - return this.tag - } - - override execute(process: Process): void { - super.execute(process) - for (let i = this.args - 1; i >= 0; i--) { - const src = process.context.popOS() - const dst = process.context.E().get_frame().get_idx(i) - process.heap.copy(dst, src) - } - // Pop function in stack - const id = process.context.popOS() - if (process.debug_mode) { - const identifier = process.debugger.identifier_map.get(id) - if (identifier) { - process.debugger.env_name_map.set(process.context.E().addr, identifier) - } - } - } -} - -export class ExitBlockInstruction extends Instruction { - constructor() { - super('EXIT_BLOCK') - } - - override execute(process: Process): void { - process.context.popRTS() - } -} diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/store.ts b/src/go-virtual-machine-main/virtual-machine/compiler/instructions/store.ts deleted file mode 100644 index 227acb1..0000000 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/store.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Process } from '../../executor/process' - -import { Instruction } from './base' - -export class StoreInstruction extends Instruction { - constructor() { - super('STORE') - } - - override execute(process: Process): void { - const dst = process.context.popOS() - const src = process.context.popOS() - process.heap.copy(dst, src) - - if (process.debug_mode) { - process.debugger.modified_buffer.add(dst) - } - } -} diff --git a/src/go-virtual-machine-main/virtual-machine/parser/parser.peggy b/src/go-virtual-machine-main/virtual-machine/compiler/parser.peggy similarity index 93% rename from src/go-virtual-machine-main/virtual-machine/parser/parser.peggy rename to src/go-virtual-machine-main/virtual-machine/compiler/parser.peggy index e4d5ecf..d8315c0 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/parser.peggy +++ b/src/go-virtual-machine-main/virtual-machine/compiler/parser.peggy @@ -5,11 +5,12 @@ StringLiteralToken, BinaryOperator, UnaryOperator, - SourceFileToken, + SourceFileTokens, ImportToken, FunctionDeclarationToken, VariableDeclarationToken, ConstantDeclarationToken, + TypeDeclarationToken, PrimaryExpressionToken, AssignmentStatementToken, IdentifierToken, @@ -24,8 +25,10 @@ ForStatementToken, DeferStatementToken, PrimitiveTypeToken, + DeclaredTypeToken, ArrayTypeToken, SliceTypeToken, + StructTypeToken, FunctionTypeToken, MapTypeToken, ChannelTypeToken, @@ -57,7 +60,8 @@ }} /* -The result of parsing a source file should be a single SourceFileToken. +The result of parsing a source file should be a single list of tokens, +which we shall call it SourceFileTokens. A token may be composed of many other tokens. The structure of what each token looks like can be found in each Token class. */ @@ -101,15 +105,15 @@ identifier = iden:$(letter (letter / unicode_digit)*) &{ return IdentifierToken. { return new IdentifierToken(location(), iden) } //* Integer Literals -int_lit = number:binary_lit { return IntegerLiteralToken.fromSource(location(), number, 2) } / - number:octal_lit { return IntegerLiteralToken.fromSource(location(), number, 8) } / - number:decimal_lit { return IntegerLiteralToken.fromSource(location(), number, 10) } / - number:hex_lit { return IntegerLiteralToken.fromSource(location(), number, 16) } -binary_lit = "0" "b" "_"? $binary_digits -octal_lit = "0" [oO]? "_"? $octal_digits +int_lit = number:binary_lit { return IntegerLiteralToken.fromSource(location(), number[3], 2) } / + number:octal_lit { return IntegerLiteralToken.fromSource(location(), number[3], 8) } / + number:hex_lit { return IntegerLiteralToken.fromSource(location(), number[3], 16) } / + number:decimal_lit { return IntegerLiteralToken.fromSource(location(), number, 10) } +binary_lit = "0" [bB] "_"? $binary_digits+ +octal_lit = "0" [oO] "_"? $octal_digits+ decimal_lit = $([1-9] "_"? decimal_digits?) / "0" -hex_lit = "0" [xX] "_"? $hex_digits +hex_lit = "0" [xX] "_"? $hex_digits+ binary_digits = binary_digit ("_"? binary_digit)* octal_digits = octal_digit ("_"? octal_digit)* @@ -142,9 +146,11 @@ interpreted_string_lit = '"' str:$[^\n"]* '"' { return StringLiteralToken.fromSo // Note: `TypeName TypeArgs?` is reduced to `TypeName` as generics are not supported. Type = @TypeName / TypeLit / "(" _ Type _ ")" //! TODO (P1): Support qualified identifiers for TypeName. -TypeName = iden:identifier &{ return PrimitiveTypeToken.isPrimitive(iden.identifier) } - { return new PrimitiveTypeToken(location(), iden.identifier) } - / @QualifiedIdent +TypeName = @QualifiedIdent / + (iden:identifier + { return PrimitiveTypeToken.isPrimitive(iden.identifier) + ? new PrimitiveTypeToken(location(), iden.identifier) + : new DeclaredTypeToken(location(), iden.identifier)}) TypeLit = ArrayType / StructType / PointerType / FunctionType / InterfaceType / SliceType / MapType / ChannelType //* Array Types @@ -158,8 +164,8 @@ ElementType = Type SliceType = "[" "]" element:ElementType { return new SliceTypeToken(location(), element) } //* Struct Types -StructType = "struct" _ "{" _ (_ FieldDecl _ ";"?)* _ "}" -FieldDecl = (IdentifierList Type / EmbeddedField) Tag? +StructType = "struct" _ "{" _ fields:(_ @FieldDecl _ ";"? _)* "}" { return new StructTypeToken(location(), [...fields].flat()) } +FieldDecl = list:IdentifierList _ type:(Type / EmbeddedField) _ Tag? { return {list, type} } EmbeddedField = "*"? TypeName Tag = string_lit @@ -230,10 +236,10 @@ IdentifierList = head:identifier tail:(_ "," _ @identifier _)* { return [head, . ExpressionList = head:Expression tail:(_ "," _ @Expression _)* { return [head, ...tail] } //* Type Declarations -TypeDecl = "type" _ (TypeSpec / "(" _ (_ TypeSpec _ ";"?)* _ ")") +TypeDecl = "type" _ @(TypeSpec / "(" _ (_ TypeSpec _ ";"?)* _ ")") TypeSpec = AliasDecl / TypeDef AliasDecl = identifier _ "=" _ Type -TypeDef = identifier _ TypeParameters? _ Type +TypeDef = identifier:identifier _ TypeParameters? _ type:Type { return new TypeDeclarationToken(location(), identifier, type, undefined) } TypeParameters = "[" _ TypeParamList _ ","? _ "]" TypeParamList = TypeParamDecl (_ "," _ TypeParamDecl)* TypeParamDecl = IdentifierList _ TypeConstraint @@ -252,8 +258,8 @@ VarSpec = identifiers:IdentifierList _ rest:( { return new VariableDeclarationToken(location(), identifiers, rest.varType, rest.expressions) } //* Short Variable Declarations -ShortVarDecl = identifiers:IdentifierList _ ":=" _ expressions:ExpressionList - { return new ShortVariableDeclarationToken(location(), identifiers, expressions) } +ShortVarDecl = identifiers:IdentifierList _ ":=" _ expressions:(ExpressionList / StructType) + { return new ShortVariableDeclarationToken(location(), identifiers, undefined, expressions) } //* Function Declarations // Note: TypeParameters? is omitted from FunctionDecl as we do not support generics. @@ -403,7 +409,7 @@ IncDecStmt = expression:Expression _ op:("++" / "--") //* Assignment Statements Assignment = left:ExpressionList _ op:$assign_op _ right:ExpressionList { return new AssignmentStatementToken(location(), left, op, right) } -assign_op = [\*\+]? "=" +assign_op = [\*\+\-\/]? "=" //* If Statements IfStmt = "if" _ init:(@SimpleStmt _ ";")? _ pred:Expression _ cons:Block _ @@ -487,7 +493,7 @@ DeferStmt = "defer" _ expression:Expression { return new DeferStatementToken(loc //* =============== Packages =============== //* Source File SourceFile = pkg:PackageClause _ ";"? _ imports:(_ @ImportDecl _ ";"? _)* declarations:(_ @TopLevelDecl _ ";"?)* - { return new SourceFileToken(location(), pkg, imports, declarations) } + { return new SourceFileTokens(location(), pkg, imports, declarations) } //* Package Clause PackageClause = "package" _ @PackageName diff --git a/src/go-virtual-machine-main/virtual-machine/parser/parser.ts b/src/go-virtual-machine-main/virtual-machine/compiler/parser.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/parser/parser.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/parser.ts diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens.ts diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/base.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/base.ts similarity index 81% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/base.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/base.ts index b164975..1139b33 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/base.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/base.ts @@ -1,6 +1,6 @@ -import { CompileError, Compiler } from '../../compiler' -import { Instruction } from '../../compiler/instructions' -import { Type } from '../../compiler/typing' +import { CompileError, Compiler } from '../../executor' +import { Instruction } from '../../executor/instructions' +import { Type } from '../../executor/typing' export type TokenLocation = { start: { offset: number; line: number; column: number } @@ -8,7 +8,7 @@ export type TokenLocation = { } export abstract class Token { - constructor(public type: string, public sourceLocation: TokenLocation) {} + constructor(public type: string, public sourceLocation: TokenLocation) { } abstract compileUnchecked(compiler: Compiler): Type diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/block.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/block.ts similarity index 89% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/block.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/block.ts index c213a6b..17fda15 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/block.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/block.ts @@ -1,9 +1,9 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { BlockInstruction, ExitBlockInstruction, -} from '../../compiler/instructions' -import { NoType, ReturnType, Type } from '../../compiler/typing' +} from '../../executor/instructions' +import { NoType, ReturnType, Type } from '../../executor/typing' import { Token, TokenLocation } from './base' import { StatementToken } from './statement' diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/tokens/declaration.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/declaration.ts new file mode 100644 index 0000000..a17724e --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/declaration.ts @@ -0,0 +1,393 @@ +import { env } from 'process' +import { Compiler } from '../../executor' +import { + CallInstruction, + Instruction, + LoadVariableInstruction, + StoreInstruction, +} from '../../executor/instructions' +import { ArrayType, DeclaredType, NoType, ReturnType, StructType, Type } from '../../executor/typing' + +import { Token, TokenLocation } from './base' +import { ExpressionToken, PrimaryExpressionModifierToken, PrimaryExpressionToken } from './expressions' +import { IdentifierToken } from './identifier' +import { FunctionLiteralToken } from './literals' +import { DeclaredTypeToken, PrimitiveTypeToken, StructTypeToken, TypeToken } from './type' + +export type TopLevelDeclarationToken = + | DeclarationToken + | FunctionDeclarationToken + +export class FunctionDeclarationToken extends Token { + constructor( + sourceLocation: TokenLocation, + public name: IdentifierToken, + public func: FunctionLiteralToken, + ) { + super('function_declaration', sourceLocation) + } + + override compileUnchecked(compiler: Compiler): Type { + const [frame_idx, var_idx] = compiler.context.env.declare_var( + this.name.identifier, + ) + //! TODO (P5): There is a double compilation of func.signature, once here and + //! once in the func.compile() call. Not really an issue as compiling types has + //! no side effects, but would be nice to fix. + compiler.type_environment.addType( + this.name.identifier, + this.func.signature.compile(compiler), + ) + this.func.compile(compiler) + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, this.name.identifier), + ) + this.pushInstruction(compiler, new StoreInstruction()) + return new NoType() + } +} + +export abstract class DeclarationToken extends Token { } + +export class TypeDeclarationToken extends DeclarationToken { + constructor( + sourceLocation: TokenLocation, + public identifier: IdentifierToken, + public varType: TypeToken, + ) { + super('type_declaration', sourceLocation) + } + + override compileUnchecked(compiler: Compiler): Type { + // bind varType to identifier + const { identifier, varType } = this + if (identifier === undefined && varType === undefined) { + //! TODO (P5): Golang implements this as a syntax error. Unfortunately, our current parsing + //! is unable to detect this error. A correct parser should require one of them to be present. + throw Error( + 'Either type(s) or name assignment(s) must be defined in type declaration.', + ) + } + compiler.context.env.declare_type(identifier.identifier, varType.compile(compiler)) + const expectedType = varType ? varType.compile(compiler) : undefined + compiler.type_environment.addType( + identifier.identifier, + expectedType as Type, + ) + return new NoType() + } +} + +export class ShortVariableDeclarationToken extends DeclarationToken { + constructor( + sourceLocation: TokenLocation, + public identifiers: IdentifierToken[], + // Note: A variable declaration must have at least one of varType / expressions. + public varType?: TypeToken, + public expressions?: ExpressionToken[], + ) { + super('short_variable_declaration', sourceLocation) + } + + override compileUnchecked(compiler: Compiler): Type { + const { identifiers, varType, expressions } = this + if (varType === undefined && expressions === undefined) { + //! TODO (P5): Golang implements this as a syntax error. Unfortunately, our current parsing + //! is unable to detect this error. A correct parser should require one of them to be present. + throw Error( + 'Either variable type or assignment value(s) must be defined in variable declaration.', + ) + } + + // Add identifiers to environment. + for (const identifier of identifiers) { + compiler.context.env.declare_var(identifier.identifier) + } + + const expectedType = varType ? varType.compile(compiler) : undefined + + // Compile and add identifiers to type environment. + if (expressions) { + /* + if (identifiers.length !== expressions.length) { + throw Error( + `Assignment mismatch: ${identifiers.length} variable(s) but ${expressions.length} value(s).`, + ) + } + */ + let delta = 0 + for (let i = 0; i < expressions.length; i++) { + let start = compiler.instructions.length + const expressionTypes = expressions[i].compile(compiler) + let identifier = identifiers[i + delta].identifier + if (expressionTypes instanceof ReturnType) { + for (let j = 0; j < expressionTypes.types.length; j++) { + identifier = identifiers[i + j].identifier + const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) + if (expectedType && !expectedType.assignableBy(expressionTypes.types[j])) { + throw Error( + `Cannot use ${expressionTypes.types[j]} as ${expectedType} in variable declaration`, + ) + } + compiler.type_environment.addType(identifier, expressionTypes.types[j]) + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, identifier), + ) + this.pushInstruction(compiler, new StoreInstruction()) + } + delta += expressionTypes.types.length - 1 + + // as the return values are loaded onto OS and thus popped in reverse order, + // storing them into variables should be in reverse order + // it is impossible to change how return values are loaded onto OS + // as it will conflict with other instructions such as binops. + let reverse_instructions = [] + for (let j = 0; j < expressionTypes.types.length; j++) { + compiler.instructions.pop() // store instruction gets popped + let instructionSet = [] + let a = 0 + let next = compiler.instructions.pop() + while (!(next instanceof StoreInstruction || next instanceof CallInstruction)) { + instructionSet[a] = next // load and intermediate instructions get popped + a++ + next = compiler.instructions.pop() + } + compiler.instructions.push(next) + reverse_instructions[j] = instructionSet + } + for (let j = 0; j < expressionTypes.types.length; j++) { + for (let k = reverse_instructions[j].length - 1; k >= 0; k--) { + this.pushInstruction(compiler, reverse_instructions[j][k] as Instruction) + } + this.pushInstruction(compiler, new StoreInstruction()) + } + } + else { + const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) + if (expressionTypes instanceof ArrayType) { + for (let j = start; j < compiler.instructions.length; j++) { + if (compiler.instructions[j] instanceof LoadVariableInstruction + && (compiler.instructions[j] as LoadVariableInstruction).id === "" + ) { + compiler.instructions[j] = new LoadVariableInstruction(frame_idx, var_idx, identifier) + } + } + } + if (expectedType && !expectedType.assignableBy(expressionTypes)) { + throw Error( + `Cannot use ${expressionTypes} as ${expectedType} in variable declaration`, + ) + } + compiler.type_environment.addType(identifier, expressionTypes) + if (!(expressionTypes instanceof ArrayType)) { + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, identifier), + ) + this.pushInstruction(compiler, new StoreInstruction()) + } + } + } + if (expressions instanceof StructTypeToken) { + const expressionTypes = expressions.compile(compiler) + for (let i = 0; i < identifiers.length; i++) { + compiler.type_environment.addType(identifiers[i].identifier, expressionTypes) + } + } + } else { + // Variables are uninitialized, but their type is given. + for (const identifier of identifiers) { + compiler.type_environment.addType( + identifier.identifier, + expectedType as Type, + ) + } + } + return new NoType() + } +} + +export class VariableDeclarationToken extends DeclarationToken { + constructor( + sourceLocation: TokenLocation, + public identifiers: IdentifierToken[], + // Note: A variable declaration must have at least one of varType / expressions. + public varType?: TypeToken, + public expressions?: ExpressionToken[], + ) { + super('variable_declaration', sourceLocation) + } + + override compileUnchecked(compiler: Compiler): Type { + const { identifiers, varType, expressions } = this + if (varType === undefined && expressions === undefined) { + //! TODO (P5): Golang implements this as a syntax error. Unfortunately, our current parsing + //! is unable to detect this error. A correct parser should require one of them to be present. + throw Error( + 'Either variable type or assignment value(s) must be defined in variable declaration.', + ) + } + + // Add identifiers to environment. + for (const identifier of identifiers) { + compiler.context.env.declare_var(identifier.identifier) + } + + let expectedType = varType ? varType.compile(compiler) : undefined + + // Compile and add identifiers to type environment. + if (expressions) { + /* + if (identifiers.length !== expressions.length) { + throw Error( + `Assignment mismatch: ${identifiers.length} variable(s) but ${expressions.length} value(s).`, + ) + } + */ + let delta = 0 + for (let i = 0; i < expressions.length; i++) { + let start = compiler.instructions.length + // if literal, use declared type instead of inferred primitive + let expressionTypes = expressions[i].compile(compiler) + let identifier = identifiers[i + delta].identifier + if (expressionTypes instanceof ReturnType) { + for (let j = 0; j < expressionTypes.types.length; j++) { + identifier = identifiers[i + j].identifier + const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) + if (expectedType && !expectedType.assignableBy(expressionTypes.types[j])) { + throw Error( + `Cannot use ${expressionTypes.types[j]} as ${expectedType} in variable declaration`, + ) + } + compiler.type_environment.addType(identifier, expressionTypes.types[j]) + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, identifier), + ) + this.pushInstruction(compiler, new StoreInstruction()) + } + + delta += expressionTypes.types.length - 1 + + // as the return values are loaded onto OS and thus popped in reverse order, + // storing them into variables should be in reverse order + // it is impossible to change how return values are loaded onto OS + // as it will conflict with other instructions such as binops. + let reverse_instructions = [] + for (let j = 0; j < expressionTypes.types.length; j++) { + compiler.instructions.pop() // store instruction gets popped + let instructionSet = [] + let a = 0 + let next = compiler.instructions.pop() + while (!(next instanceof StoreInstruction || next instanceof CallInstruction)) { + instructionSet[a] = next // load and intermediate instructions get popped + a++ + next = compiler.instructions.pop() + } + compiler.instructions.push(next) + reverse_instructions[j] = instructionSet + } + for (let j = 0; j < expressionTypes.types.length; j++) { + for (let k = reverse_instructions[j].length - 1; k >= 0; k--) { + this.pushInstruction(compiler, reverse_instructions[j][k] as Instruction) + } + this.pushInstruction(compiler, new StoreInstruction()) + } + } + else { + const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) + if (expressionTypes instanceof ArrayType) { + for (let j = start; j < compiler.instructions.length; j++) { + if (compiler.instructions[j] instanceof LoadVariableInstruction + && (compiler.instructions[j] as LoadVariableInstruction).id === "" + ) { + compiler.instructions[j] = new LoadVariableInstruction(frame_idx, var_idx, identifier) + } + } + } + // varType is the type of the variable to be declared + if (expectedType instanceof DeclaredType) { + // change the type of literal values, not the declared variable + let actualType = expectedType.name + let nextType = compiler.context.env.find_type(actualType)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType.name + nextType = compiler.context.env.find_type(actualType)[0] + } + if (expressions[i] instanceof PrimaryExpressionToken + && (expressions[i] as PrimaryExpressionToken).operand.type === "literal") { + if (nextType.assignableBy(expressionTypes)) { + expressionTypes = expectedType as Type + } + } + } + + if (expectedType && !expectedType.assignableBy(expressionTypes)) { + throw Error( + `Cannot use ${expressionTypes} as ${expectedType} in variable declaration`, + ) + } + compiler.type_environment.addType(identifier, expressionTypes) + if (!(expressionTypes instanceof ArrayType)) { + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, identifier), + ) + this.pushInstruction(compiler, new StoreInstruction()) + } + } + } + } else { + // Variables are uninitialized, but their type is given. + for (const identifier of identifiers) { + compiler.type_environment.addType( + identifier.identifier, + expectedType as Type, + ) + } + } + return new NoType() + } +} + +export class ConstantDeclarationToken extends DeclarationToken { + constructor( + sourceLocation: TokenLocation, + public identifiers: IdentifierToken[], + public expressions: ExpressionToken[], + public varType?: TypeToken, + ) { + super('const_declaration', sourceLocation) + } + + override compileUnchecked(compiler: Compiler): Type { + /** + * TODO: Handle Const separately, several different methods + * 1. Runtime Const and const tag to variable to make it immutable + * 2. Compile Time Const: Replace each reference to variable with Expression Token + * 3. Compile Time Const: Evaluate Expression Token literal value and replace each reference (Golang only allow compile time const) + */ + const { identifiers, varType, expressions } = this + const expectedType = varType ? varType.compile(compiler) : undefined + for (let i = 0; i < identifiers.length; i++) { + const var_name = identifiers[i].identifier + const expr = expressions[i] + const [frame_idx, var_idx] = compiler.context.env.declare_var(var_name) + const expressionType = expr.compile(compiler) + if (expectedType && !expressionType.assignableBy(expectedType)) { + throw Error( + `Cannot use ${expressionType} as ${expectedType} in constant declaration`, + ) + } + compiler.type_environment.addType(var_name, expressionType) + this.pushInstruction( + compiler, + new LoadVariableInstruction(frame_idx, var_idx, var_name), + ) + this.pushInstruction(compiler, new StoreInstruction()) + } + return new NoType() + } +} diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/expressions.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/expressions.ts similarity index 67% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/expressions.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/expressions.ts index 7d0e540..e6bf399 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/expressions.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/expressions.ts @@ -1,4 +1,4 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { BuiltinCapInstruction, BuiltinLenInstruction, @@ -9,21 +9,23 @@ import { LoadSliceElementInstruction, SelectorOperationInstruction, SliceOperationInstruction, -} from '../../compiler/instructions' -import { CallInstruction } from '../../compiler/instructions/funcs' +} from '../../executor/instructions' +import { CallInstruction } from '../../executor/instructions/funcs' import { ArrayType, BoolType, ChannelType, + DeclaredType, FunctionType, Int64Type, NoType, + ParameterType, ReturnType, SliceType, StringType, Type, TypeUtility, -} from '../../compiler/typing' +} from '../../executor/typing' import { Token, TokenLocation } from './base' import { IdentifierToken } from './identifier' @@ -76,7 +78,7 @@ export class PrimaryExpressionToken extends Token { // Hence, its compilation method must take in an extra argument. Idk if this is the correct way // to fix, but it doesn't make sense to force them to follow the structure of Token. export abstract class PrimaryExpressionModifierToken { - constructor(public type: string, public sourceLocation: TokenLocation) {} + constructor(public type: string, public sourceLocation: TokenLocation) { } abstract compile(compiler: Compiler, operandType: Type): Type pushInstruction(compiler: Compiler, ...instr: Instruction[]) { @@ -185,34 +187,112 @@ export class CallToken extends PrimaryExpressionModifierToken { } const argumentTypes = this.expressions.map((e) => e.compile(compiler)) + let argumentLength = 0 + for (let i = 0; i < argumentTypes.length; i++) { + argumentLength = argumentTypes[i] instanceof ReturnType + ? argumentLength + (argumentTypes[i] as ReturnType).types.length + : argumentLength + 1 + } this.pushInstruction(compiler, new CallInstruction( - argumentTypes[0] instanceof ReturnType ? argumentTypes[0].types.length : argumentTypes.length + argumentLength )) // We only implement variadic functions that accept any number of any type of arguments, // so variadic functions do not require type checking. if (!operandType.variadic) { - if (argumentTypes.length < operandType.parameters.length) { + if (argumentLength < operandType.parameters.length) { throw Error( `Not enough arguments in function call\n` + - `have (${TypeUtility.arrayToString(argumentTypes)})\n` + - `want (${TypeUtility.arrayToString(operandType.parameters)})`, + `have (${TypeUtility.arrayToString(argumentTypes)})\n` + + `want (${TypeUtility.arrayToString(operandType.parameters)})`, ) } - if (argumentTypes.length > operandType.parameters.length) { + if (argumentLength > operandType.parameters.length) { throw Error( `Too many arguments in function call\n` + - `have (${TypeUtility.arrayToString(argumentTypes)})\n` + - `want (${TypeUtility.arrayToString(operandType.parameters)})`, + `have (${TypeUtility.arrayToString(argumentTypes)})\n` + + `want (${TypeUtility.arrayToString(operandType.parameters)})`, ) } + let delta = 0 for (let i = 0; i < argumentTypes.length; i++) { - if (argumentTypes[i].assignableBy(operandType.parameters[i].type)) - continue - throw Error( - `Cannot use ${argumentTypes[i]} as ${operandType.parameters[i]} in argument to function call`, - ) + if (argumentTypes[i] instanceof ReturnType) { + if ((argumentTypes[i] as ReturnType).types.length > 1) { + for (let j = 0; j < (argumentTypes[i] as ReturnType).types.length; j++) { + // literals have unnamed types, so it can match a declared type + let type = (argumentTypes[i] as ReturnType).types[j] + if (this.expressions[i] instanceof PrimaryExpressionToken + && (this.expressions[i] as PrimaryExpressionToken).operand.type === "literal" + && operandType.parameters[i + j + delta] instanceof ParameterType + && operandType.parameters[i + j + delta].type instanceof DeclaredType) { + // argument is a literal, make it match type of required type by function + let actualType = operandType.parameters[i + j + delta].type as DeclaredType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if ((argumentTypes[i] as ReturnType).types[j].assignableBy(nextType)) { + type = nextType + break + } + } + if (type.assignableBy(operandType.parameters[i + j + delta].type)) + continue + throw Error( + `Cannot use ${type} as ${operandType.parameters[i + j + delta]} in argument to function call`, + ) + } + delta += (argumentTypes[i] as ReturnType).types.length - 1 + } else { + let type = argumentTypes[i] + if (this.expressions[i] instanceof PrimaryExpressionToken + && (this.expressions[i] as PrimaryExpressionToken).operand.type === "literal" + && operandType.parameters[i] instanceof ParameterType + && operandType.parameters[i].type instanceof DeclaredType) { + // argument is a literal, make it match type of required type by function + let actualType = operandType.parameters[i].type as DeclaredType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (argumentTypes[i].assignableBy(nextType)) { + type = nextType + break + } + } + if (type.assignableBy(operandType.parameters[i].type)) + continue + throw Error( + `Cannot use ${type} as ${operandType.parameters[i]} in argument to function call`, + ) + } + } else { + let type = argumentTypes[i] + if (this.expressions[i] instanceof PrimaryExpressionToken + && (this.expressions[i] as PrimaryExpressionToken).operand.type === "literal" + && operandType.parameters[i] instanceof ParameterType + && operandType.parameters[i].type instanceof DeclaredType) { + // argument is a literal, make it match type of required type by function + let actualType = operandType.parameters[i].type as DeclaredType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (argumentTypes[i].assignableBy(nextType)) { + type = nextType + break + } + } + if (type.assignableBy(operandType.parameters[i].type)) + continue + throw Error( + `Cannot use ${type} as ${operandType.parameters[i]} in argument to function call`, + ) + } } } diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/identifier.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/identifier.ts similarity index 91% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/identifier.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/identifier.ts index 2b8d441..2da3476 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/identifier.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/identifier.ts @@ -1,6 +1,6 @@ -import { Compiler } from '../../compiler' -import { LoadVariableInstruction } from '../../compiler/instructions' -import { PackageType, Type } from '../../compiler/typing' +import { Compiler } from '../../executor' +import { LoadVariableInstruction } from '../../executor/instructions' +import { PackageType, Type } from '../../executor/typing' import { Token, TokenLocation } from './base' diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/literals.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/literals.ts similarity index 72% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/literals.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/literals.ts index b93727c..7c62357 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/literals.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/literals.ts @@ -1,16 +1,22 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { FuncBlockInstruction, JumpInstruction, + LoadArrayElementInstruction, LoadArrayInstruction, LoadConstantInstruction, LoadDefaultInstruction, LoadFuncInstruction, LoadSliceInstruction, + LoadVariableInstruction, ReturnInstruction, -} from '../../compiler/instructions' + StoreArrayElementInstruction, + StoreInstruction, +} from '../../executor/instructions' +import { MemoryAllocationInstruction } from '../../executor/instructions/memory' import { ArrayType, + DeclaredType, Float64Type, FunctionType, Int64Type, @@ -18,11 +24,11 @@ import { SliceType, StringType, Type, -} from '../../compiler/typing' +} from '../../executor/typing' import { Token, TokenLocation } from './base' import { BlockToken } from './block' -import { ExpressionToken } from './expressions' +import { ExpressionToken, PrimaryExpressionToken } from './expressions' import { ArrayTypeToken, FunctionTypeToken, SliceTypeToken } from './type' export abstract class LiteralToken extends Token { @@ -48,6 +54,7 @@ export class IntegerLiteralToken extends LiteralToken { } override compileUnchecked(compiler: Compiler): Type { + // may need to change so that it can be a float as well this.pushInstruction( compiler, new LoadConstantInstruction(this.value, new Int64Type()), @@ -179,16 +186,37 @@ export class LiteralValueToken extends Token { `Array literal has ${this.elements.length} elements but only expected ${type.length}, in type ${type}.`, ) } - + let a = 0 + if (a == 0 && compiler.instructions[compiler.instructions.length - 1] instanceof StoreArrayElementInstruction) { + a += (compiler.instructions[compiler.instructions.length - 1] as StoreArrayElementInstruction).index + 1 + } for (const element of this.elements) { this.compileElement(compiler, type.element, element, 'array literal') + // load element in actual array and then store element + if (!(type.element instanceof ArrayType)) { + this.pushInstruction(compiler, new LoadVariableInstruction(0, 0, "")) + //this.pushInstruction(compiler, new LoadConstantInstruction(a, new Int64Type())) + //this.pushInstruction(compiler, new LoadArrayElementInstruction()) + //this.pushInstruction(compiler, new StoreInstruction()) + this.pushInstruction(compiler, new StoreArrayElementInstruction(a)) + a++ + } } for (let i = 0; i < type.length - this.elements.length; i++) { // Ran out of literal values, use the default values. this.pushInstruction(compiler, new LoadDefaultInstruction(type.element)) + // load element in actual array and then store element + if (!(type.element instanceof ArrayType)) { + this.pushInstruction(compiler, new LoadVariableInstruction(0, 0, "")) + //this.pushInstruction(compiler, new LoadConstantInstruction(a, new Int64Type())) + //this.pushInstruction(compiler, new LoadArrayElementInstruction()) + //this.pushInstruction(compiler, new StoreInstruction()) + this.pushInstruction(compiler, new StoreArrayElementInstruction(a)) + a++ + } } - this.pushInstruction(compiler, new LoadArrayInstruction(type.length)) + //this.pushInstruction(compiler, new LoadArrayInstruction(type.length)) } else if (type instanceof SliceType) { for (const element of this.elements) { this.compileElement(compiler, type.element, element, 'slice literal') @@ -196,7 +224,7 @@ export class LiteralValueToken extends Token { const sliceLength = this.elements.length this.pushInstruction( compiler, - new LoadArrayInstruction(sliceLength), + new LoadArrayInstruction(sliceLength, type), new LoadConstantInstruction(0, new Int64Type()), new LoadConstantInstruction(sliceLength, new Int64Type()), new LoadSliceInstruction(), @@ -217,8 +245,22 @@ export class LiteralValueToken extends Token { if (element instanceof LiteralValueToken) { element.compileWithType(compiler, type) } else { - const actualType = element.compile(compiler) - if (!type.equals(actualType)) { + let actualType = element.compile(compiler) + // make untyped element match the required type + let finalType = type + if (element instanceof PrimaryExpressionToken + && (element as PrimaryExpressionToken).operand.type === "literal" + && type instanceof DeclaredType) { + let nextType = (type as DeclaredType).type[0] + while (nextType instanceof DeclaredType) { + finalType = nextType + nextType = (finalType as DeclaredType).type[0] + } + if (actualType.assignableBy(nextType)) { + actualType = type + } + } + if (!type.equals(actualType)) { throw new Error( `Cannot use ${actualType} as ${type} value in ${typeName}.`, ) @@ -238,6 +280,15 @@ export class ArrayLiteralToken extends Token { override compileUnchecked(compiler: Compiler): Type { const type = this.arrayType.compile(compiler) + /* if (type instanceof ArrayType) { + let length = type.length + let next = type.element + while (next instanceof ArrayType) { + length = length * next.length + next = next.element + } + this.pushInstruction(compiler, new MemoryAllocationInstruction(length)) + } */ this.body.compileWithType(compiler, type) return type } diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/operator.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/operator.ts similarity index 60% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/operator.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/operator.ts index 46547d8..a5406dd 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/operator.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/operator.ts @@ -1,14 +1,15 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { BinaryInstruction, LoadChannelReqInstruction, LoadDefaultInstruction, TryChannelReqInstruction, UnaryInstruction, -} from '../../compiler/instructions' -import { BoolType, ChannelType, Type } from '../../compiler/typing' +} from '../../executor/instructions' +import { BoolType, ChannelType, DeclaredType, Type } from '../../executor/typing' import { Token, TokenLocation } from './base' +import { PrimaryExpressionToken } from './expressions' abstract class Operator extends Token { name: string @@ -76,8 +77,39 @@ export class BinaryOperator extends Operator { } override compileUnchecked(compiler: Compiler): Type { - const leftType = this.children[0].compile(compiler) - const rightType = this.children[1].compile(compiler) + // needs to find a way to determine whether to use lenient check (transitive check) + // or strict check (declared types must match exactly even if they are transitive) + let leftType = this.children[0].compile(compiler) + let rightType = this.children[1].compile(compiler) + // literals have unnamed types, so it can match a declared type + if (this.children[0] instanceof PrimaryExpressionToken + && this.children[0].operand.type === "literal" + && rightType instanceof DeclaredType) { + // LHS of the binop is a literal, make it match type of RHS + let actualType = rightType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(leftType)) { + leftType = rightType + } + } else if (this.children[1] instanceof PrimaryExpressionToken + && this.children[1].operand.type === "literal" + && leftType instanceof DeclaredType) { + // RHS of the binop is a literal, make it match type of LHS + let actualType = leftType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(rightType)) { + rightType = leftType + } + } + // special handling for literals to act as int or float if (!leftType.equals(rightType)) { throw Error( `Invalid operation (mismatched types ${leftType} and ${rightType})`, diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/source_file.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/source_file.ts similarity index 91% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/source_file.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/source_file.ts index a0470af..165292c 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/source_file.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/source_file.ts @@ -1,19 +1,19 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { BlockInstruction, CallInstruction, LoadConstantInstruction, LoadVariableInstruction, StoreInstruction, -} from '../../compiler/instructions' -import { BoolType, NoType, Type } from '../../compiler/typing' -import { builtinPackages } from '../../compiler/typing/packages' +} from '../../executor/instructions' +import { BoolType, NoType, Type } from '../../executor/typing' +import { builtinPackages } from '../../executor/typing/packages' import { Token, TokenLocation } from './base' import { TopLevelDeclarationToken } from './declaration' import { StringLiteralToken } from './literals' -export class SourceFileToken extends Token { +export class SourceFileTokens extends Token { constructor( sourceLocation: TokenLocation, public pkg: string, diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/statement.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/statement.ts similarity index 64% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/statement.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/statement.ts index c19b0d7..6129849 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/statement.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/statement.ts @@ -1,12 +1,12 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { BinaryInstruction, BlockInstruction, CallInstruction, DeferredCallInstruction, - DoneInstruction, ExitBlockInstruction, - ForkInstruction, + GoInstruction, + Instruction, LoadChannelReqInstruction, LoadConstantInstruction, PopInstruction, @@ -14,20 +14,21 @@ import { SelectInstruction, StoreInstruction, TryChannelReqInstruction, -} from '../../compiler/instructions' +} from '../../executor/instructions' import { ExitLoopInstruction, JumpIfFalseInstruction, JumpInstruction, -} from '../../compiler/instructions/control' +} from '../../executor/instructions/control' import { BoolType, ChannelType, + DeclaredType, Int64Type, NoType, ReturnType, Type, -} from '../../compiler/typing' +} from '../../executor/typing' import { Token, TokenLocation } from './base' import { BlockToken } from './block' @@ -67,7 +68,7 @@ export class AssignmentStatementToken extends Token { constructor( sourceLocation: TokenLocation, public left: ExpressionToken[], - public operation: '=' | '+=' | '*=', + public operation: '=' | '+=' | '*=' | '-=' | '/=', public right: ExpressionToken[], ) { super('assignment', sourceLocation) @@ -75,13 +76,41 @@ export class AssignmentStatementToken extends Token { override compileUnchecked(compiler: Compiler): Type { // TODO: Custom Instructions to avoid recalculation? - for (let i = 0; i < this.left.length; i++) { - const left = this.left[i] - const right = this.right[i] + for (let i = 0; i < this.right.length; i++) { + let left = this.left[i] + let right = this.right[i] let assignType: Type if (this.operation === '+=') { - const leftType = left.compile(compiler) - const rightType = right.compile(compiler) + let leftType = left.compile(compiler) + let rightType = right.compile(compiler) + // literals have unnamed types, so it can match a declared type + if (this.left[i] instanceof PrimaryExpressionToken + && (this.left[i] as PrimaryExpressionToken).operand.type === "literal" + && rightType instanceof DeclaredType) { + // LHS of the binop is a literal, make it match type of RHS + let actualType = rightType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(leftType)) { + leftType = rightType + } + } else if (this.right[i] instanceof PrimaryExpressionToken + && (this.right[i] as PrimaryExpressionToken).operand.type === "literal" + && leftType instanceof DeclaredType) { + // RHS of the binop is a literal, make it match type of LHS + let actualType = leftType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(rightType)) { + rightType = leftType + } + } if (!leftType.equals(rightType)) { throw Error( `Invalid operation (mismatched types ${leftType} and ${rightType})`, @@ -90,8 +119,36 @@ export class AssignmentStatementToken extends Token { assignType = leftType this.pushInstruction(compiler, new BinaryInstruction('sum')) } else if (this.operation === '*=') { - const leftType = left.compile(compiler) - const rightType = right.compile(compiler) + let leftType = left.compile(compiler) + let rightType = right.compile(compiler) + // literals have unnamed types, so it can match a declared type + if (this.left[i] instanceof PrimaryExpressionToken + && (this.left[i] as PrimaryExpressionToken).operand.type === "literal" + && rightType instanceof DeclaredType) { + // LHS of the binop is a literal, make it match type of RHS + let actualType = rightType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(leftType)) { + leftType = rightType + } + } else if (this.right[i] instanceof PrimaryExpressionToken + && (this.right[i] as PrimaryExpressionToken).operand.type === "literal" + && leftType instanceof DeclaredType) { + // RHS of the binop is a literal, make it match type of LHS + let actualType = leftType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(rightType)) { + rightType = leftType + } + } if (!leftType.equals(rightType)) { throw Error( `Invalid operation (mismatched types ${leftType} and ${rightType})`, @@ -99,16 +156,128 @@ export class AssignmentStatementToken extends Token { } assignType = leftType this.pushInstruction(compiler, new BinaryInstruction('product')) + } else if (this.operation === '-=') { + let leftType = left.compile(compiler) + let rightType = right.compile(compiler) + // literals have unnamed types, so it can match a declared type + if (this.left[i] instanceof PrimaryExpressionToken + && (this.left[i] as PrimaryExpressionToken).operand.type === "literal" + && rightType instanceof DeclaredType) { + // LHS of the binop is a literal, make it match type of RHS + let actualType = rightType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(leftType)) { + leftType = rightType + } + } else if (this.right[i] instanceof PrimaryExpressionToken + && (this.right[i] as PrimaryExpressionToken).operand.type === "literal" + && leftType instanceof DeclaredType) { + // RHS of the binop is a literal, make it match type of LHS + let actualType = leftType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(rightType)) { + rightType = leftType + } + } + if (!leftType.equals(rightType)) { + throw Error( + `Invalid operation (mismatched types ${leftType} and ${rightType})`, + ) + } + assignType = leftType + this.pushInstruction(compiler, new BinaryInstruction('difference')) + } else if (this.operation === '/=') { + let leftType = left.compile(compiler) + let rightType = right.compile(compiler) + // literals have unnamed types, so it can match a declared type + if (this.left[i] instanceof PrimaryExpressionToken + && (this.left[i] as PrimaryExpressionToken).operand.type === "literal" + && rightType instanceof DeclaredType) { + // LHS of the binop is a literal, make it match type of RHS + let actualType = rightType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(leftType)) { + leftType = rightType + } + } else if (this.right[i] instanceof PrimaryExpressionToken + && (this.right[i] as PrimaryExpressionToken).operand.type === "literal" + && leftType instanceof DeclaredType) { + // RHS of the binop is a literal, make it match type of LHS + let actualType = leftType + let nextType = compiler.context.env.find_type(actualType.name)[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = compiler.context.env.find_type(actualType.name)[0] + } + if (nextType.assignableBy(rightType)) { + rightType = leftType + } + } + if (!leftType.equals(rightType)) { + throw Error( + `Invalid operation (mismatched types ${leftType} and ${rightType})`, + ) + } + assignType = leftType + this.pushInstruction(compiler, new BinaryInstruction('quotient')) } else if (this.operation === '=') { assignType = right.compile(compiler) } else { throw Error('Unimplemented') } - const varType = left.compile(compiler) - if (!varType.assignableBy(assignType)) { - throw Error(`Cannot use ${assignType} as ${varType} in assignment`) + if (assignType instanceof ReturnType) { + for (let j = 0; j < assignType.types.length; j++) { + left = this.left[i] + const varType = left.compile(compiler) + if (!varType.assignableBy(assignType.types[j])) { + throw Error(`Cannot use ${assignType.types[j]} as ${varType} in assignment`) + } + this.pushInstruction(compiler, new StoreInstruction()) + i++ + } + // as the return values are loaded onto OS and thus popped in reverse order, + // storing them into variables should be in reverse order + // it is impossible to change how return values are loaded onto OS + // as it will conflict with other instructions such as binops. + let reverse_instructions = [] + for (let j = 0; j < assignType.types.length; j++) { + compiler.instructions.pop() // store instruction gets popped + let instructionSet = [] + let a = 0 + let next = compiler.instructions.pop() + while (!(next instanceof StoreInstruction || next instanceof CallInstruction)) { + instructionSet[a] = next // load and intermediate instructions get popped + a++ + next = compiler.instructions.pop() + } + compiler.instructions.push(next) + reverse_instructions[j] = instructionSet + } + for (let j = 0; j < assignType.types.length; j++) { + for (let k = reverse_instructions[j].length - 1; k >= 0; k--) { + this.pushInstruction(compiler, reverse_instructions[j][k] as Instruction) + } + this.pushInstruction(compiler, new StoreInstruction()) + } + } else { + const varType = left.compile(compiler) + if (!varType.assignableBy(assignType)) { + throw Error(`Cannot use ${assignType} as ${varType} in assignment`) + } + this.pushInstruction(compiler, new StoreInstruction()) } - this.pushInstruction(compiler, new StoreInstruction()) } return new NoType() } @@ -163,6 +332,25 @@ export class ReturnStatementToken extends Token { ) } + if (this.returns) { + for (let i = 0; i < this.returns.length; i++) { + let actualType = compiler.type_environment.expectedReturn.types[i] + let nextType = actualType + if (this.returns[i] instanceof PrimaryExpressionToken + && (this.returns[i] as PrimaryExpressionToken).operand.type === "literal" + && compiler.type_environment.expectedReturn.types[i] instanceof DeclaredType) { + nextType = (compiler.type_environment.expectedReturn.types[i] as DeclaredType).type[0] + while (nextType instanceof DeclaredType) { + actualType = nextType + nextType = (actualType as DeclaredType).type[0] + } + if (returnType.types[i].assignableBy(nextType)) { + returnType.types[i] = compiler.type_environment.expectedReturn.types[i] + } + } + } + } + if (!returnType.equals(compiler.type_environment.expectedReturn)) { throw new Error( `Cannot use ${returnType} as ${compiler.type_environment.expectedReturn} value in return statement.`, @@ -405,7 +593,6 @@ export class GoStatementToken extends Token { super('go', sourceLocation) } - /** Used in the parser to only parse function calls */ static isValidGoroutine(expression: PrimaryExpressionToken) { return ( expression.rest && @@ -415,11 +602,11 @@ export class GoStatementToken extends Token { } override compileUnchecked(compiler: Compiler): Type { - const fork_instr = new ForkInstruction() - this.pushInstruction(compiler, fork_instr) this.call.compile(compiler) - this.pushInstruction(compiler, new DoneInstruction()) - fork_instr.set_addr(compiler.instructions.length) + const call = compiler.instructions[compiler.instructions.length - 1] as CallInstruction + const go_instr = new GoInstruction(call.args) + compiler.instructions[compiler.instructions.length - 1] = go_instr + go_instr.set_addr(compiler.instructions.length) return new NoType() } } diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/type.ts b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/type.ts similarity index 59% rename from src/go-virtual-machine-main/virtual-machine/parser/tokens/type.ts rename to src/go-virtual-machine-main/virtual-machine/compiler/tokens/type.ts index 63cf4a2..7967259 100644 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/type.ts +++ b/src/go-virtual-machine-main/virtual-machine/compiler/tokens/type.ts @@ -1,8 +1,9 @@ -import { Compiler } from '../../compiler' +import { Compiler } from '../../executor' import { ArrayType, BoolType, ChannelType, + DeclaredType, Float64Type, FunctionType, Int64Type, @@ -11,8 +12,10 @@ import { ReturnType, SliceType, StringType, + StructType, Type, -} from '../../compiler/typing' +} from '../../executor/typing' +import { IdentifierToken } from './identifier' import { Token, TokenLocation } from './base' import { IntegerLiteralToken } from './literals' @@ -56,13 +59,13 @@ export class PrimitiveTypeToken extends TypeToken { this.name = name } - override compileUnchecked(_compiler: Compiler): Type { + override compileUnchecked(compiler: Compiler): Type { if (this.name === 'bool') return new BoolType() else if (this.name === 'float64') return new Float64Type() else if (this.name === 'int') return new Int64Type() else if (this.name === 'int64') return new Int64Type() else if (this.name === 'string') return new StringType() - else return new NoType() + return new NoType() } } @@ -152,3 +155,72 @@ export class ChannelTypeToken extends TypeToken { ) } } + +export class DeclaredTypeToken extends TypeToken { + name: string + constructor(sourceLocation: TokenLocation, name: string) { + super(sourceLocation) + this.name = name + } + + override compileUnchecked(compiler: Compiler): Type { + const [baseTypes, internalName] = compiler.context.env.create_type(this.name) + // load the underlying types + // need to configure to use declared type if possible + return new DeclaredType(internalName, baseTypes) + } +} + +export class StructTypeToken extends TypeToken { + constructor( + sourceLocation: TokenLocation, + public fields: Token[], + ) { + super(sourceLocation) + this.fields = fields + } + + override compileUnchecked(compiler: Compiler): Type { + // load the underlying types + // need to configure to use declared type if possible + // make sense of the fields to construct the structure of the struct + const struct = {} as Record + // this.fields.length represents the number of lines of code + // used to declare the fields of the struct + for (let i = 0; i < this.fields.length; i++) { + // get type of each field line first + const type = (this.fields[i].type as TypeToken).compile(compiler) + for (let j = 0; j < this.fields[i].list.length; j++) { + // link the identifier of each field line to the type + struct[this.fields[i].list[j].identifier] = type + } + } + /* + for (let i = 0; i < this.fields.length; i++) { + for (let j = 0; j < this.fields[i].length; j++) { + if (this.fields[0][j] != null && this.fields[0][j][0] instanceof Array) { + let type = undefined + // get type first + for (let k = 0; k < this.fields[i][j][0].length; k++) { + if (this.fields[i][j][0][k] instanceof TypeToken) { + type = this.fields[i][j][0][k].compile(compiler) + break + } + } + for (let k = 0; k < this.fields[i][j][0].length; k++) { + if (!(this.fields[i][j][0][k] instanceof TypeToken) && this.fields[i][j][0][k].length > 0) { + for (let l = 0; l < this.fields[i][j][0][k].length; l++) { + if (this.fields[i][j][0][k][l] instanceof IdentifierToken) { + var x = this.fields[i][j][0][k][l] + struct[this.fields[i][j][0][k][l].identifier] = type + } + } + } + } + } + } + } + */ + return new StructType(struct) + } +} \ No newline at end of file diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/environment.ts b/src/go-virtual-machine-main/virtual-machine/executor/environment.ts similarity index 52% rename from src/go-virtual-machine-main/virtual-machine/compiler/environment.ts rename to src/go-virtual-machine-main/virtual-machine/executor/environment.ts index 45467a6..d9eda52 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/environment.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/environment.ts @@ -1,13 +1,72 @@ import { JumpInstruction } from './instructions/control' +import { Type } from './typing' class CompileEnvironment { + declare_type(name: string, type: Type) { + const frame_idx = this.frames.length - 1 + for (const var_name of this.frames[frame_idx]) { + if (var_name === name) throw Error('Type already declared') + } + for (const var_name of this.typenames[frame_idx]) { + if (var_name === name) throw Error('Type already declared') + } + const new_len = this.typenames[frame_idx].push(name) + name = name + frame_idx // internal name + const recordToAdd = {} as Record + recordToAdd[name] = type + this.types[frame_idx].push(recordToAdd) + return [0, new_len - 1] + } + + create_type(name: string) { + let frame_idx = 0 + const frame_sz = this.frames.length - 1 + while (frame_sz >= frame_idx) { + let var_idx = this.types[frame_sz - frame_idx].length - 1 + while (var_idx >= 0) { + var x = Object.keys(this.types[frame_sz - frame_idx][var_idx]) + var y = name + (frame_sz - frame_idx) + if (Object.keys(this.types[frame_sz - frame_idx][var_idx])[0] === y) + return [Object.values(this.types[frame_sz - frame_idx][var_idx]), y] + var_idx-- + } + frame_idx++ + } + throw Error('Unable to find type: ' + name) + } + + find_type(name: string) { + let frame_idx = 0 + const frame_sz = this.frames.length - 1 + while (frame_sz >= frame_idx) { + let var_idx = this.types[frame_sz - frame_idx].length - 1 + while (var_idx >= 0) { + var x = Object.keys(this.types[frame_sz - frame_idx][var_idx]) + var y = name + if (Object.keys(this.types[frame_sz - frame_idx][var_idx])[0] === y) + return Object.values(this.types[frame_sz - frame_idx][var_idx]) + var_idx-- + } + frame_idx++ + } + throw Error('Unable to find type: ' + name) + } + + typenames: string[][] + types: Record[][] frames: string[][] constructor(parent?: CompileEnvironment) { if (!parent) { this.frames = [[]] + this.typenames = [[]] + this.types = [[]] } else { this.frames = parent.frames.slice() this.frames.push([]) + this.types = parent.types.slice() + this.types.push([]) + this.typenames = parent.typenames.slice() + this.typenames.push([]) } } @@ -31,6 +90,9 @@ class CompileEnvironment { for (const var_name of this.frames[frame_idx]) { if (var_name === name) throw Error('Variable already declared') } + for (const var_name of this.typenames[frame_idx]) { + if (var_name === name) throw Error('Variable already declared') + } const new_len = this.frames[frame_idx].push(name) return [0, new_len - 1] } diff --git a/src/go-virtual-machine-main/virtual-machine/executor/index.ts b/src/go-virtual-machine-main/virtual-machine/executor/index.ts index f49d23e..102cbfd 100644 --- a/src/go-virtual-machine-main/virtual-machine/executor/index.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/index.ts @@ -1,16 +1,38 @@ -import { Instruction } from '../compiler/instructions' -import { TokenLocation } from '../parser/tokens' +import { Token, TokenLocation } from '../compiler/tokens' -import { Process } from './process' +import { TypeEnvironment } from './typing/type_environment' +import { CompileContext } from './environment' +import { DoneInstruction, Instruction } from './instructions' -const execute_instructions = ( - instrs: Instruction[], - heapsize: number, - symbols: (TokenLocation | null)[], - visualisation = false, -) => { - const process = new Process(instrs, heapsize, symbols, visualisation) - return process.start() +export class CompileError extends Error { + constructor(message: string, public sourceLocation: TokenLocation) { + super(message) + } } -export { execute_instructions } +export class Compiler { + instructions: Instruction[] = [] + symbols: (TokenLocation | null)[] = [] + context = new CompileContext() + type_environment = new TypeEnvironment() + + compile_program(token: Token) { + token.compile(this) + this.instructions.push(new DoneInstruction()) + } + + throwCompileError(message: string, sourceLocation: TokenLocation): never { + throw new CompileError(message, sourceLocation) + } +} + +const compile_tokens = (tokens: Token) => { + const compiler = new Compiler() + compiler.compile_program(tokens) + return { + instructions: compiler.instructions, + symbols: compiler.symbols, + } +} + +export { compile_tokens } diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/base.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/base.ts similarity index 93% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/base.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/base.ts index 55c0d82..5a0f1cc 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/base.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/base.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' export abstract class Instruction { tag: string diff --git a/src/go-virtual-machine-main/virtual-machine/executor/instructions/block.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/block.ts new file mode 100644 index 0000000..2930c6b --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/block.ts @@ -0,0 +1,158 @@ +import { Process } from '../../runtime/process' +import { FrameNode } from '../../heap/types/environment' +import { ArrayType, BoolType, DeclaredType, StructType, Type } from '../typing' + +import { Instruction } from './base' +import { PrimitiveTypeToken } from '../../compiler/tokens' +import { ArrayNode } from '../../heap/types/array' + +export class BlockInstruction extends Instruction { + frame: Type[] = [] + identifiers: string[] = [] + constructor(public name: string, public for_block = false) { + super('BLOCK') + } + + set_frame(frame: Type[]) { + this.frame = [...frame] + } + + set_identifiers(identifiers: string[]) { + this.identifiers = [...identifiers] + } + + override toString(): string { + return super.toString() + ' ' + this.name + } + + override execute(process: Process): void { + // make structs contiguous too + const new_frame = FrameNode.create(this.frame.length, process.heap) + process.heap.temp_push(new_frame.addr) + for (let i = 0; i < this.frame.length; i++) { + const T = this.frame[i] + if (T instanceof DeclaredType) { + // Find underlying type to load default values into + let actualType = T + let nextType = T.type + // TODO: Morph to support structs + while (nextType[0] instanceof DeclaredType) { + actualType = nextType[0] + nextType = actualType.type + } + new_frame.set_idx(nextType[0].defaultNodeCreator()(process.heap), i) + } else if (T instanceof ArrayType) { + let dimensions = [] as number[] + let length = T.length + let next = T.element + dimensions.push(length) + while (next instanceof ArrayType) { + dimensions.push(next.length) + length = length * next.length + next = next.element + } + if (next instanceof DeclaredType) { + // Find underlying type to load default values into + let actualType = next + let nextType = next.type + // TODO: Morph to support structs + while (nextType[0] instanceof DeclaredType) { + actualType = nextType[0] + nextType = actualType.type + } + next = nextType[0] + } + let addr = next.bulkDefaultNodeCreator()(process.heap, length) + let sizeof = 2 + if (next instanceof BoolType) sizeof = 1 + let arrayNodes = [] as ArrayNode[] + if (T.element instanceof ArrayType) { + let next2 = T.element + while (next2.element instanceof ArrayType) { + next2 = next2.element + } + let baseType = next2.element + if (baseType instanceof BoolType) sizeof = 1 + let addr2 = addr + // handle multi-dimensional arrays: inner-most layer + // we ensured that the memory block is contiguous earlier + // so we need to link ArrayNodes to the correct memory addresses + for (let a = 0; a < length / next2.length; a++) { + arrayNodes.push(ArrayNode.create(next2.length, process.heap, sizeof, addr2)) + addr2 += sizeof * next2.length + } + dimensions.pop() + while (dimensions.length > 0) { + let dim = dimensions.pop() + let n = arrayNodes.length + for (let a = 0; a < n / dim; a++) { + let array = ArrayNode.create(dim, process.heap, sizeof, addr) + for (let b = 0; b < dim; b++) { + array.set_child(b, arrayNodes.shift().addr) + } + arrayNodes.push(array) + } + } + new_frame.set_idx(arrayNodes.pop().addr, i) + } else { + // in the case of 1D array + let array = ArrayNode.create(T.length, process.heap, sizeof, addr) + new_frame.set_idx(array.addr, i) + } + } else { + new_frame.set_idx(T.defaultNodeCreator()(process.heap), i) + } + } + const new_env = process.context + .E() + .extend_env(new_frame.addr, this.for_block).addr + process.context.pushRTS(new_env) + process.heap.temp_pop() + + if (process.debug_mode) { + process.debugger.env_alloc_map.set(new_env, process.runtime_count) + process.debugger.env_name_map.set(new_env, this.name) + const children = new_frame.get_children() + for (let i = 0; i < children.length; i++) { + process.debugger.identifier_map.set(children[i], this.identifiers[i]) + } + } + } +} +export class FuncBlockInstruction extends BlockInstruction { + constructor(public args: number) { + super('ANONY FUNC', false) + this.tag = 'FUNC_BLOCK' + } + + override toString(): string { + return this.tag + } + + override execute(process: Process): void { + super.execute(process) + for (let i = this.args - 1; i >= 0; i--) { + const src = process.context.popOS() + const dst = process.context.E().get_frame().get_idx(i) + process.heap.copy(dst, src) + } + // Pop function in stack + const id = process.context.popOS() + if (process.debug_mode) { + const identifier = process.debugger.identifier_map.get(id) + if (identifier) { + process.debugger.env_name_map.set(process.context.E().addr, identifier) + } + } + } +} + +export class ExitBlockInstruction extends Instruction { + constructor() { + super('EXIT_BLOCK') + } + + override execute(process: Process): void { + process.context.popRTS() + } +} diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/builtin.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/builtin.ts similarity index 78% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/builtin.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/builtin.ts index 9c2e0a8..a41bcb8 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/builtin.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/builtin.ts @@ -1,8 +1,9 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { ArrayNode, SliceNode } from '../../heap/types/array' import { IntegerNode } from '../../heap/types/primitives' import { Instruction } from './base' +import { ChannelArrayNode } from '../../heap/types/channel' /** Takes an object address from the OS, and returns the length of that object. */ export class BuiltinLenInstruction extends Instruction { @@ -12,7 +13,7 @@ export class BuiltinLenInstruction extends Instruction { override execute(process: Process): void { const node = process.heap.get_value(process.context.popOS()) - if (node instanceof ArrayNode || node instanceof SliceNode) { + if (node instanceof ArrayNode || node instanceof SliceNode || node instanceof ChannelArrayNode) { const length = node.length() process.context.pushOS(IntegerNode.create(length, process.heap).addr) } else { @@ -29,7 +30,7 @@ export class BuiltinCapInstruction extends Instruction { override execute(process: Process): void { const node = process.heap.get_value(process.context.popOS()) - if (node instanceof ArrayNode || node instanceof SliceNode) { + if (node instanceof ArrayNode || node instanceof SliceNode || node instanceof ChannelArrayNode) { const capacity = node.capacity() process.context.pushOS(IntegerNode.create(capacity, process.heap).addr) } else { diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/concurrent.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/concurrent.ts similarity index 65% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/concurrent.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/concurrent.ts index 0a4f86b..a78af1c 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/concurrent.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/concurrent.ts @@ -1,13 +1,15 @@ -import { Process } from '../../executor/process' -import { ArrayNode } from '../../heap/types/array' +import { Process } from '../../runtime/process' +import { ChannelArrayNode } from '../../heap/types/channel' import { ChannelNode, ChannelReqNode, ReqInfoNode, } from '../../heap/types/channel' +import { FuncNode, MethodNode } from '../../heap/types/func' import { IntegerNode } from '../../heap/types/primitives' import { Instruction } from './base' +import { CallInstruction } from './funcs' export class ForkInstruction extends Instruction { addr: number @@ -34,6 +36,70 @@ export class ForkInstruction extends Instruction { } } +export class GoInstruction extends Instruction { + addr: number + + constructor(public args: number, addr = 0) { + super('GO') + this.addr = addr + } + + override toString(): string { + return 'GO ' + this.args.toString() + ' ARGS' + } + + set_addr(addr: number) { + this.addr = addr + } + + static is(instr: Instruction): instr is GoInstruction { + return instr.tag === 'GO' + } + + override execute(process: Process): void { + const func = process.heap.get_value(process.context.peekOSIdx(this.args)) + if (!(func instanceof FuncNode) && !(func instanceof MethodNode)) + throw Error('Stack does not contain closure') + + if (func instanceof FuncNode) { + const new_context = process.context.go() + new_context.pushRTS(func.E()) + new_context.set_PC(func.PC()) + new_context.pushOS(func.addr) + const results = [] + for (let i = this.args - 1; i >= 0; i--) { + const src = process.context.popOS() + results[i] = src + } + for (let i = 0; i < this.args; i++) { + // making it "pass by value" instead of by reference + const allocate = process.heap.allocate(process.heap.get_size(results[i])) + process.heap.copy(allocate, results[i]) + new_context.pushOS(allocate) + } + new_context.pushDeferStack() + process.contexts.push(new_context.addr) + + if (process.debug_mode) { + process.debugger.context_id_map.set( + new_context.addr, + process.debugger.context_id++, + ) + } + process.context.popOS() + } else { + // create the frame for function, put arguments in frame + // func is a methodnode + const receiver = func.receiver() + receiver.handleMethodCall(process, func.identifier(), this.args) + } + } + + static fromCallInstruction(call: CallInstruction): GoInstruction { + return new GoInstruction(call.args) + } +} + export class LoadChannelInstruction extends Instruction { constructor() { super('LDCH') @@ -91,7 +157,7 @@ export class TryChannelReqInstruction extends Instruction { const chan = chan_req.channel() const req = chan_req.req() if (!chan.try(req)) { - process.context.set_waitlist(ArrayNode.create(2, process.heap).addr) + process.context.set_waitlist(ChannelArrayNode.create(2, process.heap).addr) process.context.waitlist().set_child(0, chan.wait(req)) process.context .waitlist() @@ -143,7 +209,7 @@ export class SelectInstruction extends Instruction { } else { process.context.set_blocked(true) process.context.set_waitlist( - ArrayNode.create(cases.length + 1, process.heap).addr, + ChannelArrayNode.create(cases.length + 1, process.heap).addr, ) for (let i = 0; i < cases.length; i++) { const chan = cases[i].channel() diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/control.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/control.ts similarity index 95% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/control.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/control.ts index 3dd547a..3394ea6 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/control.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/control.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { BoolNode } from '../../heap/types/primitives' import { Instruction } from './base' diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/funcs.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/funcs.ts similarity index 96% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/funcs.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/funcs.ts index f655545..2a4fa3a 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/funcs.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/funcs.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { CallRefNode, DeferFuncNode, @@ -108,6 +108,7 @@ export class ReturnInstruction extends Instruction { // Clear remnant environment nodes on the RTS (e.g. from blocks). while (!(process.context.peekRTS() instanceof CallRefNode)) { process.context.popRTS() + if (process.context.RTS().sz() === 0) break } const defers = process.context.peekDeferStack() @@ -157,6 +158,7 @@ export class ReturnInstruction extends Instruction { process.context.popDeferStack() } + if (process.context.RTS().sz() === 0) return // handles goroutines exiting const callRef = process.heap.get_value(process.context.popRTS()) if (!(callRef instanceof CallRefNode)) throw new Error('Unreachable') process.context.set_PC(callRef.PC()) diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/index.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/index.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/index.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/index.ts diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/load.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/load.ts similarity index 95% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/load.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/load.ts index 59dca95..d42876e 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/load.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/load.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { ArrayNode, SliceNode } from '../../heap/types/array' import { FmtPkgNode } from '../../heap/types/fmt' import { @@ -69,7 +69,7 @@ export class LoadDefaultInstruction extends Instruction { * Pushes the address of the array back onto the OS. */ export class LoadArrayInstruction extends Instruction { - constructor(public length: number) { + constructor(public length: number, public type: Type) { super('LDA') } @@ -78,6 +78,8 @@ export class LoadArrayInstruction extends Instruction { } override execute(process: Process): void { + // this is for dynamic arrays (slices) only, actual arrays are allocated + // when entering function and uses a different instruction const arrayNode = ArrayNode.create(this.length, process.heap) for (let i = this.length - 1; i >= 0; i--) { arrayNode.set_child(i, process.context.popOS()) diff --git a/src/go-virtual-machine-main/virtual-machine/executor/instructions/memory.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/memory.ts new file mode 100644 index 0000000..0eeb68d --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/memory.ts @@ -0,0 +1,18 @@ +import { Process } from '../../runtime/process' +import { ArrayNode, SliceNode } from '../../heap/types/array' +import { IntegerNode } from '../../heap/types/primitives' + +import { Instruction } from './base' + +/** Allocates a memory block with the required size, and returns the starting address. */ +export class MemoryAllocationInstruction extends Instruction { + size: number + constructor(size: number) { + super('MALLOC') + this.size = size + } + + override execute(process: Process): number { + return process.context.heap.allocate(this.size) + } +} \ No newline at end of file diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/operator.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/operator.ts similarity index 95% rename from src/go-virtual-machine-main/virtual-machine/compiler/instructions/operator.ts rename to src/go-virtual-machine-main/virtual-machine/executor/instructions/operator.ts index 93e9730..19ba9a0 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/instructions/operator.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/operator.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { ArrayNode, SliceNode } from '../../heap/types/array' import { IntegerNode, @@ -7,6 +7,7 @@ import { } from '../../heap/types/primitives' import { Instruction } from './base' +import { ChannelArrayNode } from '../../heap/types/channel' export abstract class OpInstruction extends Instruction { op: string @@ -73,7 +74,7 @@ export class SliceOperationInstruction extends Instruction { // If high is not provided, its default value will be resolved later on in the code. const high = highNode instanceof IntegerNode ? highNode.get_value() : null - if (node instanceof ArrayNode) { + if (node instanceof ArrayNode || node instanceof ChannelArrayNode) { process.context.pushOS(this.sliceArray(process, node, low, high)) } else if (node instanceof SliceNode) { process.context.pushOS(this.sliceSlice(process, node, low, high)) diff --git a/src/go-virtual-machine-main/virtual-machine/executor/instructions/store.ts b/src/go-virtual-machine-main/virtual-machine/executor/instructions/store.ts new file mode 100644 index 0000000..930350c --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/executor/instructions/store.ts @@ -0,0 +1,53 @@ +import { ArrayNode } from '../../heap/types/array' +import { BoolNode } from '../../heap/types/primitives' +import { Process } from '../../runtime/process' + +import { Instruction } from './base' + +export class StoreInstruction extends Instruction { + constructor() { + super('STORE') + } + + override execute(process: Process): void { + const dst = process.context.popOS() + const src = process.context.popOS() + process.heap.copy(dst, src) + + if (process.debug_mode) { + process.debugger.modified_buffer.add(dst) + } + } +} + +export class StoreArrayElementInstruction extends Instruction { + index: number + constructor(index: number) { + super('STORE ARRAY ELEMENT') + this.index = index + } + + override execute(process: Process): void { + const dst = process.context.popOS() + const src = process.context.popOS() + const array = new ArrayNode(process.heap, dst) + /* + if (this.index < 0 || this.index >= array.length()) { + throw new Error( + `Index out of range [${this.index}] with length ${array.length()}`, + ) + } + */ + let element = array.get_child(0) + while (process.heap.get_value(element) instanceof ArrayNode) { + element = (process.heap.get_value(element) as ArrayNode).get_child(0) + } + let sizeof = 2 + if (process.heap.get_value(element) instanceof BoolNode) sizeof = 1 + process.heap.copy(element + sizeof * this.index, src) + + if (process.debug_mode) { + process.debugger.modified_buffer.add(dst) + } + } +} diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/typing/index.ts b/src/go-virtual-machine-main/virtual-machine/executor/typing/index.ts similarity index 63% rename from src/go-virtual-machine-main/virtual-machine/compiler/typing/index.ts rename to src/go-virtual-machine-main/virtual-machine/executor/typing/index.ts index 9b3990d..3ac4753 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/typing/index.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/typing/index.ts @@ -1,3 +1,4 @@ +import { compiler } from 'peggy' import { Heap } from '../../heap' import { ArrayNode, SliceNode } from '../../heap/types/array' import { ChannelNode } from '../../heap/types/channel' @@ -9,8 +10,13 @@ import { IntegerNode, StringNode, } from '../../heap/types/primitives' +import { IdentifierToken, PrimitiveTypeToken } from '../../compiler/tokens' +import { StructNode } from '../../heap/types/struct' export abstract class Type { + variadic: any + parameters: any + results: any abstract isPrimitive(): boolean abstract toString(): string abstract equals(t: Type): boolean @@ -23,6 +29,13 @@ export abstract class Type { /** Returns a function that creates a default node of this type on the heap, and returns its address. */ abstract defaultNodeCreator(): (heap: Heap) => number + /** Returns a function that sets a default node on already allocated memory, and returns its address. + * It is mainly used for arrays and structs as memory must be pre-allocated first + * to ensure that the memory is contiguous. + */ + abstract bulkDefaultNodeCreator(): (heap: Heap, length: number) => number + + /** Returns the type of selecting an identifier on the given type. */ select(identifier: string): Type { throw new Error( @@ -48,6 +61,10 @@ export class NoType extends Type { override defaultNodeCreator(): (heap: Heap) => number { throw new Error('Cannot create values of type NoType') } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + throw new Error('Cannot create values of type NoType') + } } export class BoolType extends Type { @@ -66,6 +83,10 @@ export class BoolType extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => BoolNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap, length) => BoolNode.bulkDefault(heap, length).addr + } } export class Int64Type extends Type { @@ -84,6 +105,10 @@ export class Int64Type extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => IntegerNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap, length) => IntegerNode.bulkDefault(heap, length).addr + } } export class Float64Type extends Type { @@ -102,6 +127,10 @@ export class Float64Type extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => FloatNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap, length) => FloatNode.bulkDefault(heap, length).addr + } } export class StringType extends Type { @@ -120,6 +149,10 @@ export class StringType extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => StringNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap, length) => StringNode.bulkDefault(heap, length).addr + } } export class ArrayType extends Type { @@ -144,8 +177,11 @@ export class ArrayType extends Type { } override defaultNodeCreator(): (heap: Heap) => number { - const elementCreator = this.element.defaultNodeCreator() - return (heap) => ArrayNode.default(this.length, elementCreator, heap).addr + return (heap) => ArrayNode.default(this.length, this.element, heap).addr + } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap, length) => this.element.bulkDefaultNodeCreator()(heap, length) } } @@ -169,6 +205,10 @@ export class SliceType extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => SliceNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap) => SliceNode.default(heap).addr + } } export class ParameterType extends Type { @@ -194,13 +234,18 @@ export class ParameterType extends Type { // Do nothing. return (_) => 0 } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + // Do nothing. + return (_) => 0 + } } export class FunctionType extends Type { constructor( - public parameters: ParameterType[], - public results: ReturnType, - public variadic: boolean = false, + public override parameters: ParameterType[], + public override results: ReturnType, + public override variadic: boolean = false, ) { super() } @@ -226,6 +271,10 @@ export class FunctionType extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => FuncNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap) => FuncNode.default(heap).addr + } } export class ChannelType extends Type { @@ -273,6 +322,10 @@ export class ChannelType extends Type { override defaultNodeCreator(): (heap: Heap) => number { return (heap) => ChannelNode.default(heap).addr } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + return (heap) => ChannelNode.default(heap).addr + } } export class ReturnType extends Type { @@ -301,6 +354,11 @@ export class ReturnType extends Type { throw Error('Unreachable') } + override bulkDefaultNodeCreator(): (_heap: Heap) => number { + // Return values are pushed onto the OS, and should not be allocated. + throw Error('Unreachable') + } + isVoid(): boolean { return this.types.length === 0 } @@ -327,6 +385,10 @@ export class PackageType extends Type { return (heap) => PkgNode.default(heap).addr } + override bulkDefaultNodeCreator(): (_heap: Heap) => number { + return (heap) => PkgNode.default(heap).addr + } + override select(identifier: string): Type { if (!(identifier in this.types)) { throw new Error(`undefined: ${this.name}.${identifier}`) @@ -341,3 +403,70 @@ export const TypeUtility = { return (types ?? []).map((t) => t.toString()).join(', ') }, } + +export class DeclaredType extends Type { + constructor(public name: string, public type: Type) { + super() + this.name = name + this.type = type + } + + override isPrimitive(): boolean { + return false + } + + override toString(): string { + return `type ${this.name}` + } + + override equals(t: Type): boolean { + // TODO: Morph to support structs + return t instanceof DeclaredType && t.name === this.name && this.type[0].equals(t.type[0]) + } + + override defaultNodeCreator(): (heap: Heap) => number { + // Do nothing. + return (_) => 0 + } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + // Do nothing. + return (_) => 0 + } +} + +export class StructType extends Type { + constructor(public fields: Record) { + super() + } + + override isPrimitive(): boolean { + return false + } + + override toString(): string { + return `struct ${this.fields.toString()}` + } + + override equals(t: Type): boolean { + // TODO: Morph to support structs + return t instanceof StructType + && t.fields === this.fields + } + + override defaultNodeCreator(): (heap: Heap) => number { + const creators = [] as Array<(heap: Heap) => number> + for (let key in this.fields) { + creators.push(this.fields[key].defaultNodeCreator()) + } + return (heap) => StructNode.default(this.fields, creators, heap).addr + } + + override bulkDefaultNodeCreator(): (heap: Heap, length: number) => number { + const creators = [] as Array<(heap: Heap) => number> + for (let key in this.fields) { + creators.push(this.fields[key].defaultNodeCreator()) + } + return (heap) => StructNode.default(this.fields, creators, heap).addr + } +} \ No newline at end of file diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/typing/packages.ts b/src/go-virtual-machine-main/virtual-machine/executor/typing/packages.ts similarity index 74% rename from src/go-virtual-machine-main/virtual-machine/compiler/typing/packages.ts rename to src/go-virtual-machine-main/virtual-machine/executor/typing/packages.ts index 32776e8..f86fb69 100644 --- a/src/go-virtual-machine-main/virtual-machine/compiler/typing/packages.ts +++ b/src/go-virtual-machine-main/virtual-machine/executor/typing/packages.ts @@ -1,4 +1,5 @@ import { Heap } from '../../heap' +import { MutexNode } from '../../heap/types/mutex' import { WaitGroupNode } from '../../heap/types/waitGroup' import { LoadConstantInstruction, @@ -52,6 +53,35 @@ export class WaitGroupType extends Type { } } +export class MutexType extends Type { + override isPrimitive(): boolean { + return false + } + + override toString(): string { + return `sync.Mutex` + } + + override equals(t: Type): boolean { + return t instanceof MutexType + } + + override defaultNodeCreator(): (heap: Heap) => number { + return (heap) => MutexNode.default(heap).addr + } + + override select(identifier: string): Type { + if (identifier === 'Lock') { + return new FunctionType([], new ReturnType([])) + } else if (identifier === 'Unlock') { + return new FunctionType([], new ReturnType([])) + } + throw new Error( + `.${identifier} undefined (type ${this} has no field or method ${identifier})`, + ) + } +} + /** * Builtin packages are functions that take in a single `compiler` argument, * and does all the package setup within itself. @@ -77,6 +107,7 @@ export const builtinPackages = { sync: (compiler: Compiler): Type => { const pkg = new PackageType('sync', { WaitGroup: new WaitGroupType(), + Mutex: new MutexType(), }) compiler.type_environment.addType('sync', pkg) return pkg diff --git a/src/go-virtual-machine-main/virtual-machine/compiler/typing/type_environment.ts b/src/go-virtual-machine-main/virtual-machine/executor/typing/type_environment.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/compiler/typing/type_environment.ts rename to src/go-virtual-machine-main/virtual-machine/executor/typing/type_environment.ts diff --git a/src/go-virtual-machine-main/virtual-machine/heap/index.ts b/src/go-virtual-machine-main/virtual-machine/heap/index.ts index 148b02c..97200f8 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/index.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/index.ts @@ -1,7 +1,7 @@ -import { Debugger } from '../executor/debugger' +import { Debugger } from '../runtime/debugger' import { ArrayNode, SliceNode } from './types/array' -import { ChannelNode, ChannelReqNode, ReqInfoNode } from './types/channel' +import { ChannelArrayNode, ChannelNode, ChannelReqNode, ReqInfoNode } from './types/channel' import { ContextNode } from './types/context' import { EnvironmentNode, FrameNode } from './types/environment' import { FmtPkgNode, PkgNode } from './types/fmt' @@ -13,6 +13,7 @@ import { MethodNode, } from './types/func' import { LinkedListEntryNode, LinkedListNode } from './types/linkedlist' +import { MutexNode } from './types/mutex' import { BoolNode, FloatNode, @@ -25,6 +26,7 @@ import { QueueListNode, QueueNode } from './types/queue' import { StackListNode, StackNode } from './types/stack' import { WaitGroupNode } from './types/waitGroup' import { Memory } from './memory' +import { StructNode } from './types/struct' export enum TAG { UNKNOWN = 0, @@ -55,6 +57,10 @@ export enum TAG { DEFER_METHOD = 25, PKG = 26, FMT_PKG = 27, + MUTEX = 28, + DECLARED = 29, + STRUCT = 30, + CHANNEL_ARRAY = 31, } export const word_size = 4 @@ -155,6 +161,12 @@ export class Heap { return new PkgNode(this, addr) case TAG.FMT_PKG: return new FmtPkgNode(this, addr) + case TAG.MUTEX: + return new MutexNode(this, addr) + case TAG.STRUCT: + return new StructNode(this, addr) + case TAG.CHANNEL_ARRAY: + return new ChannelArrayNode(this, addr) default: // return new UnassignedNode(this, addr) throw Error('Unknown Data Type') @@ -388,7 +400,7 @@ export class Heap { for (const root of roots) { this.mark(root) } - for (let cur_addr = 0; cur_addr < this.size; ) { + for (let cur_addr = 0; cur_addr < this.size;) { if (!this.is_free(cur_addr) && !this.is_marked(cur_addr)) { cur_addr = this.free(cur_addr) } else { diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/array.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/array.ts index 1edd4cd..9cc0cfc 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/array.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/array.ts @@ -1,6 +1,8 @@ import { Heap, TAG } from '..' +import { Type } from '../../executor/typing' import { BaseNode } from './base' +import { BoolNode, PrimitiveNode } from './primitives' /** * Each ArrayNode occupies (2 + `length`) words. @@ -8,12 +10,15 @@ import { BaseNode } from './base' * Word 1: Length of array. * Remaining `length` words: Each word is the address of an element. */ +// Should bulk allocate then export class ArrayNode extends BaseNode { - static create(length: number, heap: Heap): ArrayNode { + static create(length: number, heap: Heap, sizeof: number, startAddr: number): ArrayNode { const addr = heap.allocate(2 + length) heap.set_tag(addr, TAG.ARRAY) heap.memory.set_number(length, addr + 1) - for (let i = 0; i < length; i++) heap.memory.set_number(-1, addr + i + 2) + for (let i = 0; i < length; i++) { + heap.memory.set_word(startAddr + sizeof * i, addr + 2 + i) + } return new ArrayNode(heap, addr) } @@ -23,19 +28,18 @@ export class ArrayNode extends BaseNode { */ static default( length: number, - defaultCreator: (heap: Heap) => number, + type: Type, heap: Heap, ) { - const addr = heap.allocate(2 + length) + /* + const addr = heap.allocate(length * 2) heap.set_tag(addr, TAG.ARRAY) heap.memory.set_number(length, addr + 1) heap.temp_push(addr) - for (let i = 0; i < length; i++) heap.memory.set_number(-1, addr + i + 2) - for (let i = 0; i < length; i++) { - heap.memory.set_word(defaultCreator(heap), addr + 2 + i) - } + heap.memory.set_word(type.bulkDefaultNodeCreator()(heap, length), addr + 2) heap.temp_pop() return new ArrayNode(heap, addr) + */ } length(): number { @@ -50,10 +54,14 @@ export class ArrayNode extends BaseNode { this.heap.memory.set_word(address, this.addr + 2 + index) } + sizeof() { + return this.length() * this.heap.get_value(this.get_child(0)).sizeof() + } + get_child(index: number): number { return this.heap.memory.get_word(this.addr + 2 + index) } - + override get_children(): number[] { return [...Array(this.length()).keys()].map((x) => this.get_child(x)) } diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/base.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/base.ts index 8149019..e7878eb 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/base.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/base.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { Heap } from '..' export abstract class BaseNode { diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/channel.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/channel.ts index 477531d..760833e 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/channel.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/channel.ts @@ -196,3 +196,69 @@ export class ChannelReqNode extends BaseNode { return this.channel().toString() + '\n' + this.req().toString() } } + +/** + * Each ChannelArrayNode occupies (2 + `length`) words. + * Word 0: Array tag. + * Word 1: Length of array. + * Remaining `length` words: Each word is the address of an element. + */ +export class ChannelArrayNode extends BaseNode { + static create(length: number, heap: Heap): ChannelArrayNode { + const addr = heap.allocate(2 + length) + heap.set_tag(addr, TAG.CHANNEL_ARRAY) + heap.memory.set_number(length, addr + 1) + for (let i = 0; i < length; i++) heap.memory.set_number(-1, addr + i + 2) + return new ChannelArrayNode(heap, addr) + } + + /** + * `defaultCreator` is a function that allocates a default element on the heap, + * and returns its address. + */ + static default( + length: number, + defaultCreator: (heap: Heap) => number, + heap: Heap, + ) { + const addr = heap.allocate(2 + length) + heap.set_tag(addr, TAG.CHANNEL_ARRAY) + heap.memory.set_number(length, addr + 1) + heap.temp_push(addr) + for (let i = 0; i < length; i++) heap.memory.set_number(-1, addr + i + 2) + for (let i = 0; i < length; i++) { + heap.memory.set_word(defaultCreator(heap), addr + 2 + i) + } + heap.temp_pop() + return new ChannelArrayNode(heap, addr) + } + + length(): number { + return this.heap.memory.get_number(this.addr + 1) + } + + capacity(): number { + return this.length() + } + + set_child(index: number, address: number) { + this.heap.memory.set_word(address, this.addr + 2 + index) + } + + get_child(index: number): number { + return this.heap.memory.get_word(this.addr + 2 + index) + } + + override get_children(): number[] { + return [...Array(this.length()).keys()].map((x) => this.get_child(x)) + } + + override toString(): string { + const length = this.length() + const elements = [] + for (let i = 0; i < length; i++) { + elements.push(this.heap.get_value(this.get_child(i)).toString()) + } + return `[${elements.join(' ')}]` + } +} \ No newline at end of file diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/context.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/context.ts index 70e00ff..8357688 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/context.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/context.ts @@ -2,6 +2,7 @@ import { Heap, TAG } from '..' import { ArrayNode } from './array' import { BaseNode } from './base' +import { ChannelArrayNode } from './channel' import { EnvironmentNode } from './environment' import { CallRefNode } from './func' import { PrimitiveNode } from './primitives' @@ -12,12 +13,12 @@ export class ContextNode extends BaseNode { static create(heap: Heap) { const addr = heap.allocate(6) heap.set_tag(addr, TAG.CONTEXT) - heap.memory.set_number(0, addr + 1) + heap.memory.set_number(0, addr + 1) // PC heap.temp_push(addr) for (let i = 2; i <= 5; i++) heap.memory.set_number(-1, addr + i) - heap.memory.set_word(StackNode.create(heap).addr, addr + 2) - heap.memory.set_word(StackNode.create(heap).addr, addr + 3) - heap.memory.set_word(StackNode.create(heap).addr, addr + 5) + heap.memory.set_word(StackNode.create(heap).addr, addr + 2) // OS + heap.memory.set_word(StackNode.create(heap).addr, addr + 3) // RTS + heap.memory.set_word(StackNode.create(heap).addr, addr + 5) // DeferStack heap.temp_pop() return new ContextNode(heap, addr) } @@ -137,12 +138,19 @@ export class ContextNode extends BaseNode { return newContext } + go() { + const newContext = ContextNode.create(this.heap) + newContext.set_PC(this.PC()) + newContext.set_E(this.E().addr) + return newContext + } + set_waitlist(addr: number) { this.heap.memory.set_number(addr, this.addr + 4) } waitlist() { - return new ArrayNode(this.heap, this.heap.memory.get_number(this.addr + 4)) + return new ChannelArrayNode(this.heap, this.heap.memory.get_number(this.addr + 4)) } deferStack(): StackNode { diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/fmt.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/fmt.ts index 535c996..29f76b7 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/fmt.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/fmt.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { Heap, TAG } from '..' import { BaseNode } from './base' @@ -84,11 +84,11 @@ export class FmtPkgNode extends BaseNode { if (i > 0) { // the argument before and after the string argument will coalesce with the string argument if (process.heap.get_value(argAddresses[i]) instanceof StringNode - || (i < argCount - 1 + || (i < argCount - 1 && process.heap.get_value(argAddresses[i + 1]) instanceof StringNode) - || (i > 0 + || (i > 0 && process.heap.get_value(argAddresses[i - 1]) instanceof StringNode)) { - process.print('') + process.print('') } else { process.print(' ') } @@ -110,11 +110,11 @@ export class FmtPkgNode extends BaseNode { if (i > 0) { // the argument before and after the string argument will coalesce with the string argument if (process.heap.get_value(argAddresses[i]) instanceof StringNode - || (i < argCount - 1 + || (i < argCount - 1 && process.heap.get_value(argAddresses[i + 1]) instanceof StringNode) - || (i > 0 + || (i > 0 && process.heap.get_value(argAddresses[i - 1]) instanceof StringNode)) { - process.print('') + process.print('') } else { process.print(' ') } diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/func.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/func.ts index d084396..9d8e1d7 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/func.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/func.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { Heap, TAG } from '..' import { BaseNode } from './base' @@ -106,11 +106,19 @@ export class DeferFuncNode extends BaseNode { process.heap.memory.set_word(-1, addr + 2) const stack = StackNode.create(process.heap) + const results = [] + for (let i = argCount - 1; i >= 0; i--) { + const src = process.context.popOS() + results[i] = src + } + for (let i = 0; i < argCount; i++) { + // pass by value instead of pass by reference + const allocate = process.heap.allocate(process.heap.get_size(results[i])) + process.heap.copy(allocate, results[i]) + stack.push(allocate) + } process.heap.memory.set_word(stack.addr, addr + 2) - for (let i = 0; i < argCount; i++) stack.push(process.context.popOS()) - process.heap.memory.set_word(process.context.popOS(), addr + 1) - process.heap.temp_pop() return new DeferFuncNode(process.heap, addr) } @@ -124,11 +132,11 @@ export class DeferFuncNode extends BaseNode { } argCount(): number { - return this.heap.memory.get_number(this.addr + 2) + return this.stack().sz() } stackAddr(): number { - return this.heap.memory.get_word(this.addr + 3) + return this.heap.memory.get_word(this.addr + 2) } stack(): StackNode { @@ -160,7 +168,17 @@ export class DeferMethodNode extends BaseNode { const stack = StackNode.create(process.heap) process.heap.memory.set_word(stack.addr, addr + 2) - for (let i = 0; i < argCount; i++) stack.push(process.context.popOS()) + const results = [] + for (let i = argCount - 1; i >= 0; i--) { + const src = process.context.popOS() + results[i] = src + } + for (let i = 0; i < argCount; i++) { + // pass by value instead of pass by reference + const allocate = process.heap.allocate(process.heap.get_size(results[i])) + process.heap.copy(allocate, results[i]) + stack.push(allocate) + } const methodNode = process.context.popOS() process.heap.memory.set_word(methodNode, addr + 1) diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/mutex.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/mutex.ts new file mode 100644 index 0000000..a61fc66 --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/mutex.ts @@ -0,0 +1,111 @@ +import { Process } from '../../runtime/process' +import { Heap, TAG } from '..' + +import { BaseNode } from './base' +import { ContextNode } from './context' +import { MethodNode } from './func' +import { LinkedListEntryNode } from './linkedlist' +import { QueueNode } from './queue' +import { ChannelArrayNode } from './channel' + +/** + * Each MutexNode occupies 3 words. + * Word 0: Mutex tag. + * Word 1: Availability, -1 means it is locked, 0 means it is not locked (same as semaphores). + * Word 2: The address to a queue of waiting contexts. + */ +export class MutexNode extends BaseNode { + static create(heap: Heap): MutexNode { + const addr = heap.allocate(3) + heap.set_tag(addr, TAG.MUTEX) + heap.temp_push(addr) + heap.memory.set_number(-1, addr + 2) + heap.memory.set_number(0, addr + 1) + heap.memory.set_word(QueueNode.create(heap).addr, addr + 2) + heap.temp_pop() + return new MutexNode(heap, addr) + } + + static default(heap: Heap): MutexNode { + return MutexNode.create(heap) + } + + is_locked(): boolean { + return this.heap.memory.get_number(this.addr + 1) < 0 + } + + lock(): void { + this.heap.memory.set_number(-1, this.addr + 1) + } + + unlock(): void { + if (this.is_locked()) { + this.heap.memory.set_number(0, this.addr + 1) + } else { + throw new Error('sync: unlock of unlocked mutex') + } + } + + queue(): QueueNode { + return new QueueNode(this.heap, this.heap.memory.get_word(this.addr + 2)) + } + + override select(process: Process, identifier: string): void { + process.context.pushOS( + MethodNode.create(this.addr, identifier, this.heap).addr, + ) + } + + /** Arguments to builtin methods should be on the OS. Remember to pop the receiver from OS. */ + override handleMethodCall( + process: Process, + identifier: string, + _argCount: number, + ) { + if (identifier === 'Lock') { + this.handleLock(process) + } else if (identifier === 'Unlock') { + this.handleUnlock(process) + } + } + + handleLock(process: Process): void { + if (this.is_locked()) { + this.queue().push(process.context.addr) + process.context.set_waitlist(ChannelArrayNode.create(1, process.heap).addr) + process.context + .waitlist() + .set_child( + 0, + process.heap.blocked_contexts.push_back(process.context.addr), + ) + process.context.set_blocked(true) + } else { + this.lock() + } + } + + handleUnlock(process: Process): void { + process.context.popOS() + this.unlock() + while (this.queue().sz()) { + const context = new ContextNode(this.heap, this.queue().pop()) + const wait_nodes = context.waitlist().get_children() + for (const wait_node of wait_nodes) { + const node = new LinkedListEntryNode(this.heap, wait_node) + node.del() + } + context.set_blocked(false) + this.heap.contexts.push(context.addr) + } + } + + override get_children(): number[] { + return [this.queue().addr] + } + + override toString(): string { + return 'MUTEX LOCKED ' + this.is_locked().toString() + // throw new Error('Unimplemented') + } +} diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/primitives.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/primitives.ts index a717368..3921ba1 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/primitives.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/primitives.ts @@ -5,7 +5,7 @@ import { NumStrBinaryToBoolOp, NumUnaryOp, StrBinaryOp, -} from '../../executor/ops' +} from '../../runtime/ops' import { Heap, TAG, word_size } from '..' import { BaseNode } from './base' @@ -22,7 +22,7 @@ export abstract class PrimitiveNode extends BaseNode { export class IntegerNode extends PrimitiveNode { static create(num: number, heap: Heap) { - const addr = heap.allocate(2) + const addr = heap.allocate(IntegerNode.sizeof()) heap.set_tag(addr, TAG.NUMBER) heap.memory.set_number(num, addr + 1) return new IntegerNode(heap, addr) @@ -31,6 +31,18 @@ export class IntegerNode extends PrimitiveNode { return IntegerNode.create(0, heap) } + static bulkDefault(heap: Heap, length: number) { + const addr = heap.allocate(IntegerNode.sizeof() * length) + for (let i = 0; i < length; i++) { + heap.set_tag(addr + IntegerNode.sizeof() * i, TAG.NUMBER) + heap.memory.set_number(0, addr + 1 + IntegerNode.sizeof() * i) + } + return new IntegerNode(heap, addr) + } + static sizeof() { + return 2 + } + get_value() { return this.heap.memory.get_number(this.addr + 1) } @@ -64,15 +76,29 @@ export class IntegerNode extends PrimitiveNode { export class FloatNode extends PrimitiveNode { static create(num: number, heap: Heap) { - const addr = heap.allocate(2) + const addr = heap.allocate(FloatNode.sizeof()) heap.set_tag(addr, TAG.FLOAT) heap.memory.set_float(num, addr + 1) return new FloatNode(heap, addr) } + + static sizeof() { + return 2 + } + static default(heap: Heap) { return FloatNode.create(0.0, heap) } + static bulkDefault(heap: Heap, length: number) { + const addr = heap.allocate(FloatNode.sizeof() * length) + for (let i = 0; i < length; i++) { + heap.set_tag(addr + FloatNode.sizeof() * i, TAG.FLOAT) + heap.memory.set_float(0.0, addr + 1 + FloatNode.sizeof() * i) + } + return new FloatNode(heap, addr) + } + get_value() { return this.heap.memory.get_float(this.addr + 1) } @@ -102,15 +128,27 @@ export class FloatNode extends PrimitiveNode { export class BoolNode extends PrimitiveNode { static create(val: boolean, heap: Heap) { - const addr = heap.allocate(1) + const addr = heap.allocate(BoolNode.sizeof()) heap.set_tag(addr, TAG.BOOLEAN) heap.memory.set_bits(val ? 1 : 0, addr, 1, 16) return new BoolNode(heap, addr) } + static sizeof() { + return 1 + } static default(heap: Heap) { return BoolNode.create(false, heap) } + static bulkDefault(heap: Heap, length: number) { + const addr = heap.allocate(BoolNode.sizeof() * length) + for (let i = 0; i < length; i++) { + heap.set_tag(addr + i, TAG.BOOLEAN) + heap.memory.set_bits(0, addr + i, 1, 16) + } + return new BoolNode(heap, addr) + } + get_value() { return this.heap.memory.get_bits(this.addr, 1, 16) === 1 } @@ -133,7 +171,7 @@ export class BoolNode extends PrimitiveNode { export class StringNode extends PrimitiveNode { static create(str: string, heap: Heap) { - const addr = heap.allocate(2) + const addr = heap.allocate(StringNode.sizeof()) heap.set_tag(addr, TAG.STRING) heap.temp_push(addr) heap.memory.set_number(-1, addr + 1) @@ -154,10 +192,38 @@ export class StringNode extends PrimitiveNode { return new StringNode(heap, addr) } + static sizeof() { + return 2 + } + static default(heap: Heap) { return StringNode.create('', heap) } + static bulkDefault(heap: Heap, length: number) { + const addr = heap.allocate(StringNode.sizeof() * length) + for (let i = 0; i < length; i++) { + heap.set_tag(addr + StringNode.sizeof() * i, TAG.STRING) + heap.temp_push(addr + StringNode.sizeof() * i) + heap.memory.set_number(-1, addr + 1 + StringNode.sizeof() * i) + const list_addr = heap.allocate(Math.ceil((''.length + 1) / word_size) + 1) + heap.set_tag(list_addr, TAG.STRING_LIST) + heap.memory.set_word(list_addr, addr + 1 + StringNode.sizeof() * i) + heap.temp_pop() + for (let j = 0; j <= ''.length; j++) { + let val = 0 + if (j < ''.length) val = ''.charCodeAt(j) + heap.memory.set_bytes( + val, + Math.floor(j / word_size) + list_addr + 1, + 1, + j % word_size, + ) + } + } + return new StringNode(heap, addr) + } + get_list() { return this.heap.memory.get_word(this.addr + 1) } @@ -202,7 +268,7 @@ export class StringNode extends PrimitiveNode { throw Error('Invalid Opeartion') } } -export class StringListNode extends BaseNode {} +export class StringListNode extends BaseNode { } export class UnassignedNode extends BaseNode { static create(heap: Heap) { diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/queue.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/queue.ts index e24bf3b..c40c215 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/queue.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/queue.ts @@ -26,12 +26,24 @@ export class QueueNode extends BaseNode { list.push(addr) this.heap.memory.set_word(list.addr, this.addr + 1) } + + go(addr: number) { + const list = this.list() + list.push(addr) + this.heap.memory.set_word(list.addr, this.addr) + } + pop() { const list = this.list() const res = list.pop() this.heap.memory.set_word(list.addr, this.addr + 1) return res } + + randompeek() { + return this.list().randompeek() + } + peek() { return this.list().peek() } @@ -123,6 +135,22 @@ export class QueueListNode extends BaseNode { return val } + randompeek() { + const sz = this.get_sz() + if (sz === 0) throw Error('List Empty!') + const rand = Math.random() + const next = Math.floor(this.get_start() + + rand * (this.get_end() - this.get_start() + 1)) + const val = this.get_idx(next) + if (sz > 1) { + for (let i = next; i > this.get_start(); i--) { + this.set_idx(this.get_idx(i - 1), i) + } + this.set_idx(val, this.get_start()) + } + return this.get_idx(this.get_start()) + } + peek() { const sz = this.get_sz() if (sz === 0) throw Error('Queue List is Empty!') diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/stack.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/stack.ts index 62218c8..69625e8 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/stack.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/stack.ts @@ -14,6 +14,17 @@ export class StackNode extends BaseNode { return new StackNode(heap, addr) } + static clone(heap: Heap) { + const addr = heap.allocate(2) + heap.set_tag(addr, TAG.STACK) + if (heap.temp_roots) heap.temp_push(addr) + heap.memory.set_number(-1, addr + 1) + const list = StackListNode.clone(heap) + if (heap.temp_roots) heap.temp_pop() + heap.memory.set_word(heap.clone(list.addr), addr + 1) + return new StackNode(heap, addr) + } + list() { return new StackListNode( this.heap, @@ -55,6 +66,13 @@ export class StackListNode extends BaseNode { return new StackListNode(heap, addr) } + static clone(heap: Heap) { + const addr = heap.clone(this.init_sz) + heap.set_tag(addr, TAG.STACK_LIST) + heap.memory.set_number(0, addr + 1) + return new StackListNode(heap, addr) + } + resize(new_size: number) { const new_pos = this.heap.allocate(new_size) this.heap.set_tag(new_pos, TAG.STACK_LIST) @@ -85,7 +103,9 @@ export class StackListNode extends BaseNode { pop() { const sz = this.get_sz() - if (sz === 0) throw Error('List Empty!') + if (sz === 0) { + throw Error('List Empty!') + } const capacity = this.heap.get_size(this.addr) const val = this.get_idx(sz - 1) this.set_sz(sz - 1) @@ -95,7 +115,9 @@ export class StackListNode extends BaseNode { peek() { const sz = this.get_sz() - if (sz === 0) throw Error('List Empty!') + if (sz === 0) { + throw Error('List Empty!') + } return this.get_idx(sz - 1) } diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/struct.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/struct.ts new file mode 100644 index 0000000..33ab91a --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/struct.ts @@ -0,0 +1,76 @@ +import { Heap, TAG } from '..' +import { Type } from '../../executor/typing' +import { ArrayNode } from './array' + +import { BaseNode } from './base' + +/** + * Each ArrayNode occupies (2 + `length`) words. + * Word 0: Array tag. + * Word 1: Length of array. + * Remaining `length` words: Each word is the address of an element. + */ +export class StructNode extends BaseNode { + /* + static create(length: number, heap: Heap): StructNode { + const addr = heap.allocate(2 + length) + heap.set_tag(addr, TAG.STRUCT) + heap.memory.set_number(length, addr + 1) + for (let i = 0; i < length; i++) heap.memory.set_number(-1, addr + i + 2) + return new StructNode(heap, addr) + } + */ + + /** + * `defaultCreator` is a function that allocates a default element on the heap, + * and returns its address. + */ + static default( + fields: Record, + defaultCreator: Array<(heap: Heap) => number>, + heap: Heap, + ) { + // change it to contiguous memory + const addr = heap.allocate(2 + defaultCreator.length) + heap.set_tag(addr, TAG.STRUCT) + heap.memory.set_number(defaultCreator.length, addr + 1) + heap.temp_push(addr) + for (let i = 0; i < defaultCreator.length; i++) heap.memory.set_number(-1, addr + i + 2) + let j = 0 + for (let key in defaultCreator) { + heap.memory.set_word(defaultCreator[key](heap), addr + 2 + j) + j++ + } + heap.temp_pop() + return new StructNode(heap, addr) + } + + length(): number { + return this.heap.memory.get_number(this.addr + 1) + } + + capacity(): number { + return this.length() + } + + set_child(index: number, address: number) { + this.heap.memory.set_word(address, this.addr + 2 + index) + } + + get_child(index: number): number { + return this.heap.memory.get_word(this.addr + 2 + index) + } + + override get_children(): number[] { + return [...Array(this.length()).keys()].map((x) => this.get_child(x)) + } + + override toString(): string { + const length = this.length() + const elements = [] + for (let i = 0; i < length; i++) { + elements.push(this.heap.get_value(this.get_child(i)).toString()) + } + return `{${elements.join(' ')}}` + } +} \ No newline at end of file diff --git a/src/go-virtual-machine-main/virtual-machine/heap/types/waitGroup.ts b/src/go-virtual-machine-main/virtual-machine/heap/types/waitGroup.ts index 7aed023..8d108c7 100644 --- a/src/go-virtual-machine-main/virtual-machine/heap/types/waitGroup.ts +++ b/src/go-virtual-machine-main/virtual-machine/heap/types/waitGroup.ts @@ -1,4 +1,4 @@ -import { Process } from '../../executor/process' +import { Process } from '../../runtime/process' import { Heap, TAG } from '..' import { ArrayNode } from './array' @@ -8,6 +8,7 @@ import { MethodNode } from './func' import { LinkedListEntryNode } from './linkedlist' import { IntegerNode } from './primitives' import { QueueNode } from './queue' +import { ChannelArrayNode } from './channel' /** * Each WaitGroupNode occupies 3 words. @@ -94,7 +95,7 @@ export class WaitGroupNode extends BaseNode { process.context.popOS() if (this.count() === 0) return this.queue().push(process.context.addr) - process.context.set_waitlist(ArrayNode.create(1, process.heap).addr) + process.context.set_waitlist(ChannelArrayNode.create(1, process.heap).addr) process.context .waitlist() .set_child( diff --git a/src/go-virtual-machine-main/virtual-machine/index.ts b/src/go-virtual-machine-main/virtual-machine/index.ts index 6dfb8cc..eeec709 100644 --- a/src/go-virtual-machine-main/virtual-machine/index.ts +++ b/src/go-virtual-machine-main/virtual-machine/index.ts @@ -1,9 +1,9 @@ -import { Instruction } from './compiler/instructions' -import { StateInfo } from './executor/debugger' -import parser from './parser/parser' -import { SourceFileToken, TokenLocation } from './parser/tokens' -import { compile_tokens, CompileError } from './compiler' -import { execute_instructions } from './executor' +import { Instruction } from './executor/instructions' +import { StateInfo } from './runtime/debugger' +import parser from './compiler/parser' +import { SourceFileTokens, TokenLocation } from './compiler/tokens' +import { compile_tokens, CompileError } from './executor' +import { execute_instructions } from './runtime' interface InstructionData { val: string @@ -20,15 +20,28 @@ interface ProgramData { visualData: StateInfo[] } +interface CompileData { + output?: string + instructions: Instruction[] + symbols: (TokenLocation | null)[], + error?: { + message: string + type: 'parse' | 'compile' | 'runtime' + details?: Error | string + } + visualData: StateInfo[] +} + const runCode = ( source_code: string, heapsize: number, + deterministic = true, visualisation = true, ): ProgramData => { // Parsing. - let tokens: SourceFileToken + let tokens: SourceFileTokens try { - tokens = parser.parse(source_code) as SourceFileToken + tokens = parser.parse(source_code) as SourceFileTokens console.log(tokens) } catch (err) { const message = (err as Error).message @@ -71,6 +84,7 @@ const runCode = ( instructions, heapsize, symbols, + deterministic, visualisation, ) if (result.errorMessage) { @@ -80,7 +94,7 @@ const runCode = ( output: result.errorMessage, error: { message: result.errorMessage, - type: 'runtime', + type: 'runtime', details: result.errorMessage, }, visualData: [], @@ -95,4 +109,4 @@ const runCode = ( } } -export { type InstructionData, type ProgramData, runCode } +export { type InstructionData, type ProgramData, runCode, type CompileData } diff --git a/src/go-virtual-machine-main/virtual-machine/parser/tokens/declaration.ts b/src/go-virtual-machine-main/virtual-machine/parser/tokens/declaration.ts deleted file mode 100644 index 7561978..0000000 --- a/src/go-virtual-machine-main/virtual-machine/parser/tokens/declaration.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { env } from 'process' -import { Compiler } from '../../compiler' -import { - LoadVariableInstruction, - StoreInstruction, -} from '../../compiler/instructions' -import { NoType, ReturnType, Type } from '../../compiler/typing' - -import { Token, TokenLocation } from './base' -import { ExpressionToken, PrimaryExpressionModifierToken, PrimaryExpressionToken } from './expressions' -import { IdentifierToken } from './identifier' -import { FunctionLiteralToken } from './literals' -import { TypeToken } from './type' - -export type TopLevelDeclarationToken = - | DeclarationToken - | FunctionDeclarationToken - -export class FunctionDeclarationToken extends Token { - constructor( - sourceLocation: TokenLocation, - public name: IdentifierToken, - public func: FunctionLiteralToken, - ) { - super('function_declaration', sourceLocation) - } - - override compileUnchecked(compiler: Compiler): Type { - const [frame_idx, var_idx] = compiler.context.env.declare_var( - this.name.identifier, - ) - //! TODO (P5): There is a double compilation of func.signature, once here and - //! once in the func.compile() call. Not really an issue as compiling types has - //! no side effects, but would be nice to fix. - compiler.type_environment.addType( - this.name.identifier, - this.func.signature.compile(compiler), - ) - this.func.compile(compiler) - this.pushInstruction( - compiler, - new LoadVariableInstruction(frame_idx, var_idx, this.name.identifier), - ) - this.pushInstruction(compiler, new StoreInstruction()) - return new NoType() - } -} - -export abstract class DeclarationToken extends Token {} - -export class ShortVariableDeclarationToken extends DeclarationToken { - constructor( - sourceLocation: TokenLocation, - public identifiers: IdentifierToken[], - public expressions: ExpressionToken[], - ) { - super('short_variable_declaration', sourceLocation) - } - - override compileUnchecked(compiler: Compiler): Type { - const { identifiers, expressions } = this - for (let i = 0; i < identifiers.length; i++) { - const var_name = identifiers[i].identifier - const expr = expressions[i] - const [frame_idx, var_idx] = compiler.context.env.declare_var(var_name) - const expressionType = expr.compile(compiler) - compiler.type_environment.addType(var_name, expressionType) - this.pushInstruction( - compiler, - new LoadVariableInstruction(frame_idx, var_idx, var_name), - ) - this.pushInstruction(compiler, new StoreInstruction()) - } - return new NoType() - } -} - -export class VariableDeclarationToken extends DeclarationToken { - constructor( - sourceLocation: TokenLocation, - public identifiers: IdentifierToken[], - // Note: A variable declaration must have at least one of varType / expressions. - public varType?: TypeToken, - public expressions?: ExpressionToken[], - ) { - super('variable_declaration', sourceLocation) - } - - override compileUnchecked(compiler: Compiler): Type { - const { identifiers, varType, expressions } = this - if (varType === undefined && expressions === undefined) { - //! TODO (P5): Golang implements this as a syntax error. Unfortunately, our current parsing - //! is unable to detect this error. A correct parser should require one of them to be present. - throw Error( - 'Either variable type or assignment value(s) must be defined in variable declaration.', - ) - } - - // Add identifiers to environment. - for (const identifier of identifiers) { - compiler.context.env.declare_var(identifier.identifier) - } - - const expectedType = varType ? varType.compile(compiler) : undefined - - // Compile and add identifiers to type environment. - if (expressions) { - /* - if (identifiers.length !== expressions.length) { - throw Error( - `Assignment mismatch: ${identifiers.length} variable(s) but ${expressions.length} value(s).`, - ) - } - */ - for (let i = 0; i < identifiers.length; i++) { - - const expressionTypes = expressions[i].compile(compiler) - if (expressionTypes instanceof ReturnType) { - if (expressionTypes.types.length > 1) { - i += expressionTypes.types.length - 1 - for (let j = 0; j < expressionTypes.types.length; j++) { - const identifier = identifiers[i].identifier - const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) - if (expectedType && !expectedType.assignableBy(expressionTypes.types[j])) { - throw Error( - `Cannot use ${expressionTypes.types[j]} as ${expectedType} in variable declaration`, - ) - } - compiler.type_environment.addType(identifier, expressionTypes.types[j]) - this.pushInstruction( - compiler, - new LoadVariableInstruction(frame_idx, var_idx, identifier), - ) - this.pushInstruction(compiler, new StoreInstruction()) - i-- - } - i += expressionTypes.types.length - } - } - else { - const identifier = identifiers[i].identifier - const [frame_idx, var_idx] = compiler.context.env.find_var(identifier) - if (expectedType && !expectedType.assignableBy(expressionTypes)) { - throw Error( - `Cannot use ${expressionTypes} as ${expectedType} in variable declaration`, - ) - } - compiler.type_environment.addType(identifier, expressionTypes) - this.pushInstruction( - compiler, - new LoadVariableInstruction(frame_idx, var_idx, identifier), - ) - this.pushInstruction(compiler, new StoreInstruction()) - } - } - } else { - // Variables are uninitialized, but their type is given. - for (const identifier of identifiers) { - compiler.type_environment.addType( - identifier.identifier, - expectedType as Type, - ) - } - } - return new NoType() - } -} - -export class ConstantDeclarationToken extends DeclarationToken { - constructor( - sourceLocation: TokenLocation, - public identifiers: IdentifierToken[], - public expressions: ExpressionToken[], - public varType?: TypeToken, - ) { - super('const_declaration', sourceLocation) - } - - override compileUnchecked(compiler: Compiler): Type { - /** - * TODO: Handle Const separately, several different methods - * 1. Runtime Const and const tag to variable to make it immutable - * 2. Compile Time Const: Replace each reference to variable with Expression Token - * 3. Compile Time Const: Evaluate Expression Token literal value and replace each reference (Golang only allow compile time const) - */ - const { identifiers, varType, expressions } = this - const expectedType = varType ? varType.compile(compiler) : undefined - for (let i = 0; i < identifiers.length; i++) { - const var_name = identifiers[i].identifier - const expr = expressions[i] - const [frame_idx, var_idx] = compiler.context.env.declare_var(var_name) - const expressionType = expr.compile(compiler) - if (expectedType && !expressionType.assignableBy(expectedType)) { - throw Error( - `Cannot use ${expressionType} as ${expectedType} in constant declaration`, - ) - } - compiler.type_environment.addType(var_name, expressionType) - this.pushInstruction( - compiler, - new LoadVariableInstruction(frame_idx, var_idx, var_name), - ) - this.pushInstruction(compiler, new StoreInstruction()) - } - return new NoType() - } -} diff --git a/src/go-virtual-machine-main/virtual-machine/executor/debugger.ts b/src/go-virtual-machine-main/virtual-machine/runtime/debugger.ts similarity index 96% rename from src/go-virtual-machine-main/virtual-machine/executor/debugger.ts rename to src/go-virtual-machine-main/virtual-machine/runtime/debugger.ts index e2c78ef..509c697 100644 --- a/src/go-virtual-machine-main/virtual-machine/executor/debugger.ts +++ b/src/go-virtual-machine-main/virtual-machine/runtime/debugger.ts @@ -1,8 +1,8 @@ -import { Instruction } from '../compiler/instructions' +import { Instruction } from '../executor/instructions' import { Heap } from '../heap' import { ContextNode } from '../heap/types/context' import { EnvironmentNode } from '../heap/types/environment' -import { TokenLocation } from '../parser/tokens' +import { TokenLocation } from '../compiler/tokens' export type OSInfo = { val: string @@ -62,7 +62,7 @@ export class Debugger { public heap: Heap, public instructions: Instruction[], public symbols: (TokenLocation | null)[], - ) {} + ) { } /** * Finds all environments that can be reached from a given addr @@ -137,11 +137,15 @@ export class Debugger { /** * Generate OS Info */ + const a = context.OS() + const b = a.list() + const c = b.get_children() const OS = context .OS() .list() .get_children() .map((x) => { + const y = this.identifier_map const var_name = this.identifier_map.get(x) return { val: diff --git a/src/go-virtual-machine-main/virtual-machine/runtime/index.ts b/src/go-virtual-machine-main/virtual-machine/runtime/index.ts new file mode 100644 index 0000000..da9f4a1 --- /dev/null +++ b/src/go-virtual-machine-main/virtual-machine/runtime/index.ts @@ -0,0 +1,17 @@ +import { Instruction } from '../executor/instructions' +import { TokenLocation } from '../compiler/tokens' + +import { Process } from './process' + +const execute_instructions = ( + instrs: Instruction[], + heapsize: number, + symbols: (TokenLocation | null)[], + deterministic: boolean, + visualisation = false, +) => { + const process = new Process(instrs, heapsize, symbols, deterministic, visualisation) + return process.start() +} + +export { execute_instructions } diff --git a/src/go-virtual-machine-main/virtual-machine/executor/ops.ts b/src/go-virtual-machine-main/virtual-machine/runtime/ops.ts similarity index 100% rename from src/go-virtual-machine-main/virtual-machine/executor/ops.ts rename to src/go-virtual-machine-main/virtual-machine/runtime/ops.ts diff --git a/src/go-virtual-machine-main/virtual-machine/executor/process.ts b/src/go-virtual-machine-main/virtual-machine/runtime/process.ts similarity index 81% rename from src/go-virtual-machine-main/virtual-machine/executor/process.ts rename to src/go-virtual-machine-main/virtual-machine/runtime/process.ts index ee40b74..da4d1ab 100644 --- a/src/go-virtual-machine-main/virtual-machine/executor/process.ts +++ b/src/go-virtual-machine-main/virtual-machine/runtime/process.ts @@ -1,11 +1,11 @@ import * as seedrandom from 'seedrandom' -import { DoneInstruction, Instruction } from '../compiler/instructions' +import { DoneInstruction, Instruction } from '../executor/instructions' import { Heap } from '../heap' import { ContextNode } from '../heap/types/context' import { EnvironmentNode, FrameNode } from '../heap/types/environment' import { QueueNode } from '../heap/types/queue' -import { TokenLocation } from '../parser/tokens' +import { TokenLocation } from '../compiler/tokens' import { Debugger, StateInfo } from './debugger' @@ -25,10 +25,12 @@ export class Process { debug_mode: boolean debugger: Debugger runtime_count = 0 + deterministic: boolean constructor( instructions: Instruction[], heapsize: number, symbols: (TokenLocation | null)[], + deterministic: boolean, visualmode = false, ) { this.instructions = instructions @@ -47,6 +49,7 @@ export class Process { this.context.set_E(base_env.addr) const randomSeed = Math.random().toString(36).substring(2) this.generator = seedrandom.default(randomSeed) + this.deterministic = deterministic this.debug_mode = visualmode this.debugger = new Debugger(this.heap, this.instructions, symbols) @@ -59,13 +62,18 @@ export class Process { } start(): ProcessOutput { + const time_quantum = 30 + this.runtime_count = 0 + let completed = false + let a = 0 try { - const time_quantum = 30 - this.runtime_count = 0 - let completed = false const main_context = this.contexts.peek() while (this.contexts.sz()) { - this.context = new ContextNode(this.heap, this.contexts.peek()) + if (this.deterministic) { + this.context = new ContextNode(this.heap, this.contexts.peek()) + } else { + this.context = new ContextNode(this.heap, this.contexts.randompeek()) + } let cur_time = 0 while (!DoneInstruction.is(this.instructions[this.context.PC()])) { if (cur_time >= time_quantum) { @@ -74,6 +82,7 @@ export class Process { break } const pc = this.context.PC() + a = pc const instr = this.instructions[this.context.incr_PC()] // console.log('ctx:', this.context.addr) // console.log('Instr:', instr, this.context.PC() - 1) @@ -83,8 +92,14 @@ export class Process { // this.context.heap.print_freelist() this.runtime_count += 1 cur_time += 1 + if (this.context.addr !== main_context && this.context.RTS().sz() === 0) { + // thread has completed + break + } if (this.debug_mode) this.debugger.generate_state(pc, this.stdout) - if (this.context.is_blocked()) break + if (this.context.is_blocked()) { + break + } } if ( DoneInstruction.is(this.instructions[this.context.PC()]) && @@ -99,7 +114,7 @@ export class Process { // console.log('PC', this.contexts.get_vals()) } if (!completed && !this.heap.blocked_contexts.is_empty()) - throw Error('All threads are blocked!') + throw Error('all goroutines are asleep - deadlock!') return { stdout: this.stdout,

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