[Fix] 修复无法调用类函数的问题

[Feat] Context merge功能
[Feat] VSCode 拓展现已更为 fig-vscode.
This commit is contained in:
2025-12-23 01:15:35 +08:00
parent 50a4705551
commit 6226059adc
28 changed files with 3682 additions and 264 deletions

View File

@@ -47,7 +47,7 @@
│ ├── evaluator.hpp # Interpreter and Control flows │ ├── evaluator.hpp # Interpreter and Control flows
│ ├── warning.hpp # STD-Warnings │ ├── warning.hpp # STD-Warnings
├── ExampleCodes/ # Sample programs ├── ExampleCodes/ # Sample programs
├── VscodeExtension/ # vscode extension ├── fig-vscode/ # vscode extension
├── .clang-format # Clang format styles ├── .clang-format # Clang format styles
├── test.fig # Test file (dev) ├── test.fig # Test file (dev)
├── LICENSE # Fig project license ├── LICENSE # Fig project license

View File

@@ -47,7 +47,7 @@
│ ├── evaluator.hpp # 解释器和控制流 │ ├── evaluator.hpp # 解释器和控制流
│ ├── warning.hpp # 标准警告 │ ├── warning.hpp # 标准警告
├── ExampleCodes/ # 示例程序 ├── ExampleCodes/ # 示例程序
├── VscodeExtension/ # vscode代码插件 ├── fig-vscode/ # vscode代码插件
├── .clang-format # Clang 格式化风格 ├── .clang-format # Clang 格式化风格
├── test.fig # 测试文件(开发用) ├── test.fig # 测试文件(开发用)
├── LICENSE # Fig 项目许可证 ├── LICENSE # Fig 项目许可证

View File

@@ -1,4 +0,0 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

View File

@@ -1,3 +0,0 @@
# fig-languague-syntax README
Nothing

View File

@@ -1,82 +0,0 @@
{
"comments": {
"lineComment": "//",
"blockComment": [
"/*",
"*/"
]
},
"brackets": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
[
"\"",
"\""
],
[
"/\"",
"\"/"
]
],
"autoClosingPairs": [
{
"open": "{",
"close": "}"
},
{
"open": "[",
"close": "]"
},
{
"open": "(",
"close": ")"
},
{
"open": "\"",
"close": "\"",
"notIn": [
"string"
]
},
{
"open": "/\"",
"close": "\"/"
}
],
"surroundingPairs": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
[
"\"",
"\""
],
[
"/\"",
"\"/"
]
],
"indentationRules": {
"increaseIndentPattern": "^(?=.*(\\{|\\()|.*/\\\").*$",
"decreaseIndentPattern": "^\\s*[}\\)]|\\s*\"/"
}
}

View File

@@ -1,33 +0,0 @@
{
"name": "fig-languague-syntax",
"displayName": "Fig Languague Syntax",
"description": ":)",
"version": "0.0.1",
"engines": {
"vscode": "^1.96.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [
{
"id": "fig",
"extensions": [
".fl"
],
"aliases": [
"Fig"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "fig",
"scopeName": "source.fig",
"path": "./syntaxes/fig.tmLanguage.json"
}
]
}
}

View File

@@ -1,90 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Fig",
"scopeName": "source.fig",
"fileTypes": [
".fl"
],
"patterns": [
{
"name": "comment.line.double-slash",
"match": "//.*"
},
{
"name": "comment.block",
"begin": "/\\*",
"end": "\\*/",
"captures": {
"0": {
"name": "comment.block.fig"
}
}
},
{
"name": "keyword.control",
"match": "\\b(if|else|for|while|continue|break|return|or|not)\\b"
},
{
"name": "keyword.declaration",
"match": "\\b(var|val|func|module)\\b"
},
{
"name": "storage.type",
"match": "\\b(Int32|Int64|Float|Double|Map|Bool|Null|String)\\b"
},
{
"name": "entity.name.function",
"match": "(?<=\\bfunc\\b)\\s+\\w+"
},
{
"name": "keyword.operator.arrow",
"match": "->"
},
{
"name": "keyword.operator",
"match": "[+\\-*/%&|><!]=?|&&|\\|\\||=="
},
{
"name": "string.quoted.double",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape",
"match": "\\\\."
}
]
},
{
"name": "string.quoted.multiline",
"begin": "\\/\\\"",
"end": "\\\"/",
"patterns": [
{
"name": "constant.character.escape",
"match": "\\\\."
}
]
},
{
"name": "constant.numeric.integer",
"match": "\\b\\d+\\b"
},
{
"name": "constant.numeric.float",
"match": "\\b\\d+\\.\\d+([eE][+-]?\\d+)?[f]?\\b"
},
{
"name": "punctuation.curly",
"match": "[{}]"
},
{
"name": "punctuation.parenthesis",
"match": "[()]"
},
{
"name": "punctuation.square",
"match": "[\\[\\]]"
}
]
}

View File

@@ -1,29 +0,0 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
* `syntaxes/figlang.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
## Get up and running straight away
* Make sure the language configuration settings in `language-configuration.json` are accurate.
* Press `F5` to open a new window with your extension loaded.
* Create a new file with a file name suffix matching your language.
* Verify that syntax highlighting works and that the language configuration settings are working.
## Make changes
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Add more language features
* To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
## Install your extension
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.

5
fig-vscode/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
out
dist
node_modules
.vscode-test/
*.vsix

View File

@@ -0,0 +1,5 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

11
fig-vscode/.vscodeignore Normal file
View File

@@ -0,0 +1,11 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

View File

@@ -1,6 +1,6 @@
# Change Log # Change Log
All notable changes to the "fig-languague-syntax" extension will be documented in this file. All notable changes to the "fig-vscode" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

71
fig-vscode/README.md Normal file
View File

@@ -0,0 +1,71 @@
# fig-vscode README
This is the README for your extension "fig-vscode". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: Enable/disable this extension.
* `myExtension.thing`: Set to `blah` to do something.
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
---
## Following extension guidelines
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
## Working with Markdown
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
## For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@@ -0,0 +1,27 @@
import typescriptEslint from "typescript-eslint";
export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint.plugin,
},
languageOptions: {
parser: typescriptEslint.parser,
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],
curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];

3179
fig-vscode/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

55
fig-vscode/package.json Normal file
View File

@@ -0,0 +1,55 @@
{
"name": "fig-vscode",
"displayName": "Fig Language",
"description": "VSCode extension for Fig language with syntax highlighting",
"version": "0.0.1",
"engines": {
"vscode": "^1.90.0"
},
"categories": [
"Programming Languages"
],
"activationEvents": [],
"main": "./out/extension.js",
"contributes": {
"languages": [
{
"id": "fig",
"aliases": [
"Fig"
],
"extensions": [
".fig"
],
"configuration": "./language-configuration.json"
}
],
"semanticTokenModifiers": [
{
"fig": {
"variable": "variable.other.fig",
"function": "entity.name.function.fig"
}
}
],
"grammars": [
{
"language": "fig",
"scopeName": "source.fig",
"path": "./syntaxes/fig.tmLanguage.json"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"typescript": "^5.2.2",
"vscode": "^1.90.0",
"@types/node": "^20.6.0"
}
}

View File

@@ -0,0 +1,7 @@
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
console.log('Fig extension is now active!');
}
export function deactivate() {}

View File

@@ -0,0 +1,25 @@
{
"comments": {
"lineComment": "//",
"blockComment": ["/*", "*/"]
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"" },
{ "open": "'", "close": "'" }
],
"surroundingPairs": [
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"" },
{ "open": "'", "close": "'" }
]
}

View File

@@ -0,0 +1,15 @@
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

View File

@@ -0,0 +1,114 @@
{
"name": "Fig",
"scopeName": "source.fig",
"patterns": [
{ "include": "#comments" },
{ "include": "#strings" },
{ "include": "#numbers" },
{ "include": "#keywords" },
{ "include": "#operators" },
{ "include": "#functions" },
{ "include": "#identifiers" }
],
"repository": {
"comments": {
"patterns": [
{ "name": "comment.line.double-slash.fig", "match": "//.*$" },
{ "name": "comment.block.fig", "begin": "/\\*", "end": "\\*/" }
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.fig",
"begin": "\"\"\"",
"end": "\"\"\"",
"patterns": [{ "match": ".", "name": "string.content.fig" }]
},
{
"name": "string.quoted.double.fig",
"begin": "\"",
"end": "\"",
"patterns": [
{ "match": "\\\\.", "name": "constant.character.escape.fig" }
]
},
{
"name": "string.quoted.raw.fig",
"begin": "r\"",
"end": "\"",
"patterns": [{ "match": ".", "name": "string.content.fig" }]
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.float.fig",
"match": "\\d*\\.\\d+([eE][+-]?\\d+)?"
},
{
"name": "constant.numeric.integer.fig",
"match": "\\d+([eE][+-]?\\d+)?"
}
]
},
"keywords": {
"patterns": [
{
"name": "keyword.control.fig",
"match": "\\b(and|or|not|import|func|var|const|final|while|for|if|else|struct|interface|implement|public|return|break|continue)\\b"
},
{ "name": "constant.language.fig", "match": "\\b(true|false|null)\\b" }
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.arithmetic.fig",
"match": "(\\+|\\-|\\*|/|%|\\*\\*)"
},
{
"name": "keyword.operator.assignment.fig",
"match": "(=|\\+=|\\-=|\\*=|/=|%=|\\^=|:=)"
},
{
"name": "keyword.operator.logical.fig",
"match": "(&&|\\|\\||\\b(and|or|not)\\b)"
},
{
"name": "keyword.operator.comparison.fig",
"match": "(==|!=|<=|>=|<|>)"
},
{
"name": "punctuation.separator.fig",
"match": "[\\(\\)\\[\\]\\{\\},;:.]"
},
{
"name": "keyword.operator.other.fig",
"match": "(\\+\\+|--|->|=>|<<|>>|\\^|&|\\||~)"
}
]
},
"functions": {
"patterns": [
{
"name": "entity.name.function.fig",
"begin": "\\bfunc\\s+([a-zA-Z_][a-zA-Z0-9_]*)",
"beginCaptures": {
"1": { "name": "entity.name.function.fig" }
},
"end": "(?=;)"
}
]
},
"identifiers": {
"patterns": [
{
"name": "variable.other.fig",
"match": "(?!\\bfunc\\b)[a-zA-Z_][a-zA-Z0-9_]*"
}
]
}
}
}

17
fig-vscode/tsconfig.json Normal file
View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"outDir": "out",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"strict": true, /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}

View File

@@ -0,0 +1,44 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
## Run tests
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
* See the output of the test result in the Test Results view.
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns.
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
* Integrate to the [report issue](https://code.visualstudio.com/api/get-started/wrapping-up#issue-reporting) flow to get issue and feature requests reported by users.

View File

@@ -46,6 +46,16 @@ namespace Fig
return scopeName; return scopeName;
} }
void merge(const Context& c)
{
varTypes.insert(c.varTypes.begin(), c.varTypes.end());
variables.insert(c.variables.begin(), c.variables.end());
ams.insert(c.ams.begin(), c.ams.end());
functions.insert(c.functions.begin(), c.functions.end());
functionNames.insert(c.functionNames.begin(), c.functionNames.end());
structTypeNames.insert(c.structTypeNames.begin(), c.structTypeNames.end());
}
std::optional<ObjectPtr> get(const FString &name) std::optional<ObjectPtr> get(const FString &name)
{ {
auto it = variables.find(name); auto it = variables.find(name);

View File

@@ -15,6 +15,7 @@ namespace Fig
class EvaluatorError final : public AddressableError class EvaluatorError final : public AddressableError
{ {
public: public:
const char* errorName = errName;
virtual FString toString() const override virtual FString toString() const override
{ {
std::string msg = std::format("[Eve: {}] {} in [{}] {}", errName, std::string(this->message.begin(), this->message.end()), this->src_loc.file_name(), this->src_loc.function_name()); std::string msg = std::format("[Eve: {}] {} in [{}] {}", errName, std::string(this->message.begin(), this->message.end()), this->src_loc.file_name(), this->src_loc.function_name());
@@ -27,6 +28,11 @@ namespace Fig
AddressableError(_msg, aai.line, aai.column, loc) AddressableError(_msg, aai.line, aai.column, loc)
{ {
} }
virtual FString getErrorType() const override
{
return FString("[Eval]" + std::string(errorName));
}
}; };
struct StatementResult struct StatementResult
{ {

View File

@@ -33,9 +33,8 @@ namespace Fig
case Operator::BitNot: return std::make_shared<Object>(bit_not(*lhs)); case Operator::BitNot: return std::make_shared<Object>(bit_not(*lhs));
case Operator::ShiftLeft: return std::make_shared<Object>(shift_left(*lhs, *rhs)); case Operator::ShiftLeft: return std::make_shared<Object>(shift_left(*lhs, *rhs));
case Operator::ShiftRight: return std::make_shared<Object>(shift_right(*lhs, *rhs)); case Operator::ShiftRight: return std::make_shared<Object>(shift_right(*lhs, *rhs));
case Operator::Assign: case Operator::Assign: {
{
*lhs = *rhs; *lhs = *rhs;
return Object::getNullInstance(); return Object::getNullInstance();
} }
@@ -63,25 +62,64 @@ namespace Fig
} }
const StructInstance &st = lhs->as<StructInstance>(); const StructInstance &st = lhs->as<StructInstance>();
Ast::VarExpr varExp; Ast::VarExpr varExp;
if (!(varExp = std::dynamic_pointer_cast<Ast::VarExprAst>(binExp->rexp))) Ast::FunctionCall fnCall;
if ((varExp = std::dynamic_pointer_cast<Ast::VarExprAst>(binExp->rexp)))
{
FString member = varExp->name;
auto structTypeNameOpt = currentContext->getStructName(st.parentId);
if (!structTypeNameOpt) throw RuntimeError(FStringView("Can't get struct type name"));
FString structTypeName = *structTypeNameOpt;
if (!st.localContext->containsInThisScope(member))
{
static constexpr char NoAttributeError[] = "NoAttributeError";
throw EvaluatorError<NoAttributeError>(FStringView(
std::format("Struct `{}` has no attribute '{}'", structTypeName.toBasicString(), member.toBasicString())),
binExp->rexp->getAAI());
}
return *st.localContext->get(member); // safe
}
else if ((fnCall = std::dynamic_pointer_cast<Ast::FunctionCallExpr>(binExp->rexp)))
{
auto structTypeNameOpt = currentContext->getStructName(st.parentId);
if (!structTypeNameOpt) throw RuntimeError(FStringView("Can't get struct type name"));
FString structTypeName = *structTypeNameOpt;
FString fnName = u8"<anonymous>";
if (auto var = std::dynamic_pointer_cast<Ast::VarExprAst>(fnCall->callee))
fnName = var->name; // function in struct has its name, so we can get the name
if (!st.localContext->containsInThisScope(fnName))
{
static constexpr char NoAttributeError[] = "NoAttributeError";
throw EvaluatorError<NoAttributeError>(FStringView(
std::format("Struct `{}` has no attribute '{}'", structTypeName.toBasicString(), fnName.toBasicString())),
binExp->rexp->getAAI());
}
auto calleeValOpt = st.localContext->get(fnName);
ObjectPtr calleeVal = *calleeValOpt;
if (!calleeVal->is<Function>())
{
static constexpr char NotAFunctionErrorName[] = "NotAFunctionError";
throw EvaluatorError<NotAFunctionErrorName>(
FStringView(std::format(
"'{}' is not a function or callable",
calleeVal->toString().toBasicString())),
currentAddressInfo);
}
Function fn = calleeVal->as<Function>();
return evalFunctionCall(fn, fnCall->arg, fnName);
}
else
{ {
static constexpr char AccessOpNotAFieldNameError[] = "AccessOpNotAFieldNameError"; static constexpr char AccessOpNotAFieldNameError[] = "AccessOpNotAFieldNameError";
throw EvaluatorError<AccessOpNotAFieldNameError>(FStringView( throw EvaluatorError<AccessOpNotAFieldNameError>(FStringView(
std::format("{} is not a field name", binExp->rexp->toString().toBasicString())), std::format("{} is not a field", binExp->rexp->toString().toBasicString())),
binExp->rexp->getAAI()); binExp->rexp->getAAI());
} }
FString member = varExp->name;
auto structTypeNameOpt = currentContext->getStructName(st.parentId);
if (!structTypeNameOpt) throw RuntimeError(FStringView("Can't get struct type name"));
FString structTypeName = *structTypeNameOpt;
if (!st.localContext->containsInThisScope(member))
{
static constexpr char NoAttributeError[] = "NoAttributeError";
throw EvaluatorError<NoAttributeError>(FStringView(
std::format("Struct `{}` has no attribute '{}'", structTypeName.toBasicString(), member.toBasicString())),
binExp->rexp->getAAI());
}
return *st.localContext->get(member); // safe
} }
return __evalOp(binExp->op, eval(binExp->lexp), eval(binExp->rexp)); return __evalOp(binExp->op, eval(binExp->lexp), eval(binExp->rexp));
} }
@@ -417,6 +455,7 @@ namespace Fig
} }
} }
} }
instanceCtx->merge(*structT.defContext);
return std::make_shared<Object>(StructInstance(structT.id, instanceCtx)); return std::make_shared<Object>(StructInstance(structT.id, instanceCtx));
} }
default: default:
@@ -538,7 +577,29 @@ namespace Fig
} }
fields.push_back(Field(field.am, field.fieldName, TypeInfo(field.tiName), field.defaultValueExpr)); fields.push_back(Field(field.am, field.fieldName, TypeInfo(field.tiName), field.defaultValueExpr));
} }
ContextPtr defContext(currentContext); ContextPtr defContext = std::make_shared<Context>(FString(std::format("<Struct {} at {}:{}>",
stDef->name.toBasicString(),
stDef->getAAI().line,
stDef->getAAI().column)),
currentContext);
ContextPtr previousContext = currentContext;
currentContext = defContext;
const Ast::BlockStatement &body = stDef->body;
for (auto &st : body->stmts)
{
if (st->getType() != Ast::AstType::FunctionDefSt)
{
static constexpr char UnexpectedStatementInStructError[] = "UnexpectedStatementInStructError";
throw EvaluatorError<UnexpectedStatementInStructError>(FStringView(
std::format("Unexpected statement `{}` in struct declaration",
st->toString().toBasicString())),
st->getAAI());
}
evalStatement(st); // function def st
}
currentContext = previousContext;
AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const); AccessModifier am = (stDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
TypeInfo _(stDef->name, true); // register type name TypeInfo _(stDef->name, true); // register type name
currentContext->def( currentContext->def(

View File

@@ -1,3 +1,10 @@
var x := 3.141; struct test
{
func foo()
{
__fstdout_println("666");
}
}
__fstdout_println(x); var x := test{};
x.foo();