├── .gitattributes ├── .github ├── copilot-instructions.md └── workflows │ ├── lpc-build.yml │ ├── node.js.yml │ └── release.yml ├── .gitignore ├── .prettierignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.lib.js ├── build.mjs ├── client ├── package-lock.json ├── package.json ├── src │ ├── ProgressIndicator.ts │ ├── configuration │ │ ├── configuration.node.ts │ │ ├── configuration.ts │ │ ├── languageDescription.ts │ │ └── languageIds.ts │ ├── documentSelector.ts │ ├── extension.ts │ ├── fileSchemes.ts │ ├── languageFeatures │ │ ├── jsDocCompletions.ts │ │ ├── semanticTokens.ts │ │ └── utilities.ts │ ├── protocol │ │ └── protocol.ts │ ├── task │ │ ├── lpcConfigProvider.ts │ │ └── taskProvider.ts │ ├── typeConverters.ts │ └── utils │ │ ├── dispose.ts │ │ ├── platform.ts │ │ └── utils.ts └── tsconfig.json ├── config-changes.md ├── efuns ├── fluffos │ ├── arrays.h │ ├── async.h │ ├── buffers.h │ ├── calls.h │ ├── contrib.h │ ├── db.h │ ├── driver.h │ ├── ed.h │ ├── efuns.fluffos.h │ ├── external.h │ ├── filesystem.h │ ├── floats.h │ ├── functions.h │ ├── general.h │ ├── interactive.h │ ├── internals.h │ ├── lpc-config.json │ ├── mappings.h │ ├── misc.h │ ├── mudlib.h │ ├── numbers.h │ ├── objects.h │ ├── parsing.h │ ├── pcre.h │ ├── sockets.h │ ├── strings.h │ ├── system.h │ └── zh-cn │ │ ├── arrays.zh-cn.h │ │ ├── async.zh-cn.h │ │ ├── buffers.zh-cn.h │ │ ├── calls.zh-cn.h │ │ ├── contrib.zh-cn.h │ │ ├── db.zh-cn.h │ │ ├── ed.zh-cn.h │ │ ├── efuns.fluffos.h │ │ ├── external.zh-cn.h │ │ ├── filesystem.zh-cn.h │ │ ├── floats.zh-cn.h │ │ ├── functions.zh-cn.h │ │ ├── general.zh-cn.h │ │ ├── interactive.zh-cn.h │ │ ├── internals.zh-cn.h │ │ ├── mappings.zh-cn.h │ │ ├── misc.zh-cn.h │ │ ├── mudlib.zh-cn.h │ │ ├── numbers.zh-cn.h │ │ ├── objects.zh-cn.h │ │ ├── parsing.zh-cn.h │ │ ├── pcre.zh-cn.h │ │ ├── sockets.zh-cn.h │ │ ├── strings.zh-cn.h │ │ └── system.zh-cn.h └── ldmud │ ├── defines.h │ ├── efun.h │ ├── efuns.ldmud.h │ ├── lpc-config.json │ └── obsolete.h ├── grammar ├── LPCLexer.g4 └── LPCParser.g4 ├── jest.config.ts ├── language-configuration.json ├── lib ├── README.md └── package.json ├── lpc-icon.png ├── package-lock.json ├── package.json ├── schemas ├── lpc-config.schema.json └── lpc.schema.json ├── server ├── package-lock.json ├── package.json ├── src │ ├── cancellationToken │ │ ├── cancellationToken.ts │ │ ├── serverCancellationToken.ts │ │ └── tsconfig.json │ ├── cli │ │ ├── _namespaces │ │ │ └── lpc.ts │ │ └── lpc.ts │ ├── compiler │ │ ├── LpcConfig.ts │ │ ├── _namespaces │ │ │ ├── lpc.moduleSpecifiers.ts │ │ │ ├── lpc.performance.ts │ │ │ └── lpc.ts │ │ ├── binder.ts │ │ ├── builderPublic.ts │ │ ├── checker.ts │ │ ├── commandLineParser.ts │ │ ├── core.ts │ │ ├── corePublic.ts │ │ ├── debug.ts │ │ ├── diagnosticInformation.ts │ │ ├── emitter.ts │ │ ├── executeCommandLine.ts │ │ ├── expressionToTypeNode.ts │ │ ├── factory │ │ │ ├── baseNodeFactory.ts │ │ │ ├── emitHelper.ts │ │ │ ├── emitNode.ts │ │ │ ├── nodeChildren.ts │ │ │ ├── nodeConverters.ts │ │ │ ├── nodeFactory.ts │ │ │ ├── parenthesizerRules.ts │ │ │ ├── utilities.ts │ │ │ └── utilitiesPublic.ts │ │ ├── lpcFileHandler.ts │ │ ├── lpcJsHelpers.ts │ │ ├── lpcbuild.ts │ │ ├── lpcbuildPublic.ts │ │ ├── moduleNameResolver.ts │ │ ├── moduleSpecifiers.ts │ │ ├── nodeTests.ts │ │ ├── parser.ts │ │ ├── path.ts │ │ ├── perfLoger.ts │ │ ├── performance.ts │ │ ├── performanceCore.ts │ │ ├── program.ts │ │ ├── resolutionCache.ts │ │ ├── resolver.ts │ │ ├── scanner.ts │ │ ├── sourcemap.ts │ │ ├── sys.ts │ │ ├── tracing.ts │ │ ├── transformers.ts │ │ ├── transformers │ │ │ └── declarations.ts │ │ ├── types.ts │ │ ├── utilities.ts │ │ ├── utilitiesPublic.ts │ │ ├── visitorPublic.ts │ │ ├── watch.ts │ │ ├── watchPublic.ts │ │ └── watchUtilities.ts │ ├── config-types.ts │ ├── harness │ │ └── harnessIO.ts │ ├── lpc │ │ ├── _namespaces │ │ │ ├── lpc.server.ts │ │ │ └── lpc.ts │ │ └── lpc.ts │ ├── lpcserver │ │ ├── MarkdownString.ts │ │ ├── document.ts │ │ ├── nodeServer.ts │ │ ├── openJsDocLink.ts │ │ ├── previewer.ts │ │ ├── protocol.const.ts │ │ ├── server.ts │ │ ├── textRendering.ts │ │ ├── typeConverters.ts │ │ └── utils.ts │ ├── parse-fluff-docs.ts │ ├── parse-ld-docs.ts │ ├── server.ts │ ├── server │ │ ├── _namespaces │ │ │ ├── lpc.server.protocol.ts │ │ │ ├── lpc.server.ts │ │ │ └── lpc.ts │ │ ├── editorServices.ts │ │ ├── project.ts │ │ ├── protocol.ts │ │ ├── scriptInfo.ts │ │ ├── scriptVersionCache.ts │ │ ├── session.ts │ │ ├── types.ts │ │ ├── utilities.ts │ │ └── utilitiesPublic.ts │ ├── services │ │ ├── _namespaces │ │ │ ├── lpc.Completions.StringCompletions.ts │ │ │ ├── lpc.Completions.ts │ │ │ ├── lpc.FindAllReferences.ts │ │ │ ├── lpc.GoToDefinition.ts │ │ │ ├── lpc.JsDoc.ts │ │ │ ├── lpc.NavigationBar.ts │ │ │ ├── lpc.Rename.ts │ │ │ ├── lpc.SignatureHelp.ts │ │ │ ├── lpc.SymbolDisplay.ts │ │ │ ├── lpc.codefix.ts │ │ │ ├── lpc.formatting.ts │ │ │ ├── lpc.textChanges.ts │ │ │ └── lpc.ts │ │ ├── classifier2020.ts │ │ ├── codefixes │ │ │ ├── helpers.ts │ │ │ └── importFixes.ts │ │ ├── completions.ts │ │ ├── documentRegistry.ts │ │ ├── exportInfoMap.ts │ │ ├── findAllReferences.ts │ │ ├── formatting │ │ │ ├── formatting.ts │ │ │ ├── formattingContext.ts │ │ │ ├── rule.ts │ │ │ ├── rules.ts │ │ │ ├── rulesMap.ts │ │ │ └── smartIndenter.ts │ │ ├── goToDefinition.ts │ │ ├── importTracker.ts │ │ ├── jsDoc.ts │ │ ├── navigationBar.ts │ │ ├── rename.ts │ │ ├── services.ts │ │ ├── signatureHelp.ts │ │ ├── sourcemaps.ts │ │ ├── stringCompletions.ts │ │ ├── suggestionDiagnostics.ts │ │ ├── symbolDisplay.ts │ │ ├── textChanges.ts │ │ ├── types.ts │ │ └── utilities.ts │ ├── tests │ │ ├── TestFileHandler.ts │ │ ├── __snapshots__ │ │ │ └── compiler.spec.ts.snap │ │ ├── _namespaces │ │ │ ├── lpc.server.ts │ │ │ └── lpc.ts │ │ ├── cases │ │ │ └── compiler │ │ │ │ ├── arity1.c │ │ │ │ ├── arity2.c │ │ │ │ ├── array1.c │ │ │ │ ├── array2.c │ │ │ │ ├── array3.c │ │ │ │ ├── array4.c │ │ │ │ ├── array5.c │ │ │ │ ├── array6.c │ │ │ │ ├── array7.c │ │ │ │ ├── assignment1.c │ │ │ │ ├── assignment2.c │ │ │ │ ├── assignment3.c │ │ │ │ ├── assignment4.c │ │ │ │ ├── assignment5.c │ │ │ │ ├── assignmentArraySpread.c │ │ │ │ ├── atBlock1.c │ │ │ │ ├── atBlock2.c │ │ │ │ ├── atBlock3.c │ │ │ │ ├── atBlock4.c │ │ │ │ ├── atBlock5.c │ │ │ │ ├── badBreak.c │ │ │ │ ├── badContinue.c │ │ │ │ ├── badInitializer.c │ │ │ │ ├── badLocalInit.c │ │ │ │ ├── badSwitch.c │ │ │ │ ├── buffer1.c │ │ │ │ ├── buffer2.c │ │ │ │ ├── bytes1.c │ │ │ │ ├── callOther1.c │ │ │ │ ├── callOther2.c │ │ │ │ ├── callOther3.c │ │ │ │ ├── callOther4.c │ │ │ │ ├── callOther5.c │ │ │ │ ├── catchBlock.c │ │ │ │ ├── catchBlock2.c │ │ │ │ ├── catchBlock3.c │ │ │ │ ├── catchBlock4.c │ │ │ │ ├── catchBlock5.c │ │ │ │ ├── catchExpr1.c │ │ │ │ ├── catchStmt1.c │ │ │ │ ├── catchStmt2.c │ │ │ │ ├── charLiteral1.c │ │ │ │ ├── class1.c │ │ │ │ ├── class2.c │ │ │ │ ├── class3.c │ │ │ │ ├── class4.c │ │ │ │ ├── clone_object1.c │ │ │ │ ├── clone_object2.c │ │ │ │ ├── closure1.c │ │ │ │ ├── closure2.c │ │ │ │ ├── closure3.c │ │ │ │ ├── closure4.c │ │ │ │ ├── closure5.c │ │ │ │ ├── closure6.c │ │ │ │ ├── closure7.c │ │ │ │ ├── closure8.c │ │ │ │ ├── closureFuncShortcut1.c │ │ │ │ ├── closureFuncShortcut2.c │ │ │ │ ├── commaExpr.c │ │ │ │ ├── declarations1.c │ │ │ │ ├── declarations2.c │ │ │ │ ├── declarations3.c │ │ │ │ ├── declarations4.c │ │ │ │ ├── declarations5.c │ │ │ │ ├── declarations6.c │ │ │ │ ├── defaultArgs.c │ │ │ │ ├── defaultArgs2.c │ │ │ │ ├── defaultArgs3.c │ │ │ │ ├── define1.c │ │ │ │ ├── define2.c │ │ │ │ ├── define3.c │ │ │ │ ├── defineNull.c │ │ │ │ ├── defineUndefined.c │ │ │ │ ├── deprecated1.c │ │ │ │ ├── deprecated2.c │ │ │ │ ├── deprecated3.c │ │ │ │ ├── doWhile.c │ │ │ │ ├── efun.fluff.filter.c │ │ │ │ ├── error1.c │ │ │ │ ├── error2.c │ │ │ │ ├── eval1.c │ │ │ │ ├── evaluate1.c │ │ │ │ ├── evaluate2.c │ │ │ │ ├── evaluate3.c │ │ │ │ ├── expr1.c │ │ │ │ ├── expr2.c │ │ │ │ ├── expr3.c │ │ │ │ ├── expr4.c │ │ │ │ ├── expr5.c │ │ │ │ ├── flowNode1.c │ │ │ │ ├── flowType1.c │ │ │ │ ├── flowType2.c │ │ │ │ ├── flowType3.c │ │ │ │ ├── fnNoReturn1.c │ │ │ │ ├── fnNoReturn2.c │ │ │ │ ├── fnNoReturn3.c │ │ │ │ ├── for1.c │ │ │ │ ├── for2.c │ │ │ │ ├── for3.c │ │ │ │ ├── for4.c │ │ │ │ ├── forEach1.c │ │ │ │ ├── forEach10.c │ │ │ │ ├── forEach11.c │ │ │ │ ├── forEach2.c │ │ │ │ ├── forEach3.c │ │ │ │ ├── forEach4.c │ │ │ │ ├── forEach5.c │ │ │ │ ├── forEach6.c │ │ │ │ ├── forEach7.c │ │ │ │ ├── forEach8.c │ │ │ │ ├── forEach9.c │ │ │ │ ├── forEachRef.c │ │ │ │ ├── forEachRef2.c │ │ │ │ ├── funcDecl1.c │ │ │ │ ├── funcDecl2.c │ │ │ │ ├── funcSignature1.c │ │ │ │ ├── funcSignature2.c │ │ │ │ ├── functionCall1.c │ │ │ │ ├── functionCall2.c │ │ │ │ ├── functionCall3.c │ │ │ │ ├── functionCall4.c │ │ │ │ ├── functionCall5.c │ │ │ │ ├── functionCall6.c │ │ │ │ ├── identifier1.c │ │ │ │ ├── if1.c │ │ │ │ ├── if2.c │ │ │ │ ├── if3.c │ │ │ │ ├── ifelse.c │ │ │ │ ├── in1.c │ │ │ │ ├── include1.c │ │ │ │ ├── include2.c │ │ │ │ ├── includeFile.h │ │ │ │ ├── indexAccess.c │ │ │ │ ├── indexAccess2.c │ │ │ │ ├── inherit1.base1.c │ │ │ │ ├── inherit1.base2.c │ │ │ │ ├── inherit1.c │ │ │ │ ├── intLiteral1.c │ │ │ │ ├── intLiteral2.c │ │ │ │ ├── intersectionType.c │ │ │ │ ├── intersectionTypeIllegal.c │ │ │ │ ├── jsDocParam.c │ │ │ │ ├── lambda1.c │ │ │ │ ├── lpc-ignore.c │ │ │ │ ├── lpc-nocheck.c │ │ │ │ ├── lpcDocParam1.c │ │ │ │ ├── lpcDocVar1.c │ │ │ │ ├── lpcDocVar2.c │ │ │ │ ├── lpcDocVar3.c │ │ │ │ ├── lpcDocVar4.c │ │ │ │ ├── lpcDocVar5.c │ │ │ │ ├── lpcDocVar6.c │ │ │ │ ├── lpcDocVar7.c │ │ │ │ ├── lpcDocVarTagBase.c │ │ │ │ ├── macro1.c │ │ │ │ ├── macro2.c │ │ │ │ ├── macro3.c │ │ │ │ ├── macro4.c │ │ │ │ ├── mapping1.c │ │ │ │ ├── mapping2.c │ │ │ │ ├── mapping3.c │ │ │ │ ├── mapping4.c │ │ │ │ ├── mapping5.c │ │ │ │ ├── mapping6.c │ │ │ │ ├── mappingType1.c │ │ │ │ ├── mappingType2.c │ │ │ │ ├── missingFunc.c │ │ │ │ ├── modifiers1.c │ │ │ │ ├── modifiers2.c │ │ │ │ ├── modifiers3.c │ │ │ │ ├── namedObject1.c │ │ │ │ ├── namedObject2.c │ │ │ │ ├── namedObject3.c │ │ │ │ ├── namedObject4.c │ │ │ │ ├── namedObject5.c │ │ │ │ ├── namedObject6.c │ │ │ │ ├── new1.c │ │ │ │ ├── new2.c │ │ │ │ ├── new3.c │ │ │ │ ├── new4.c │ │ │ │ ├── new5.c │ │ │ │ ├── new6.c │ │ │ │ ├── object.c │ │ │ │ ├── object2.c │ │ │ │ ├── operatorBitwise.c │ │ │ │ ├── operatorDoubleBang.c │ │ │ │ ├── operatorLogical.c │ │ │ │ ├── paramRef.c │ │ │ │ ├── predefined1.c │ │ │ │ ├── predefined2.c │ │ │ │ ├── preproc_conditional.c │ │ │ │ ├── preproc_conditional_macro.c │ │ │ │ ├── return1.c │ │ │ │ ├── string1.c │ │ │ │ ├── string2.c │ │ │ │ ├── stringizedIdentifier.c │ │ │ │ ├── struct1.c │ │ │ │ ├── struct2.c │ │ │ │ ├── struct3.c │ │ │ │ ├── struct4.c │ │ │ │ ├── structMemberAccess.c │ │ │ │ ├── structMemberAccess2.c │ │ │ │ ├── super1.c │ │ │ │ ├── super2.c │ │ │ │ ├── switch1.c │ │ │ │ ├── switch2.c │ │ │ │ ├── switch3.c │ │ │ │ ├── ternary.c │ │ │ │ ├── thisObject1.c │ │ │ │ ├── thisObject1.file2.c │ │ │ │ ├── typeAssertion1.c │ │ │ │ ├── typeAssertion2.c │ │ │ │ ├── typeAssertion3.c │ │ │ │ ├── typeInference1.c │ │ │ │ ├── typeInference2.c │ │ │ │ ├── typeInference3.c │ │ │ │ ├── typePredicate1.c │ │ │ │ ├── typePredicate2.c │ │ │ │ ├── typePredicate3.c │ │ │ │ ├── unionTypes.c │ │ │ │ ├── utf8.c │ │ │ │ ├── varBeforeDecl.c │ │ │ │ ├── varBeforeDecl2.c │ │ │ │ ├── varBeforeDecl3.c │ │ │ │ ├── variadic1.c │ │ │ │ ├── variadic2.c │ │ │ │ └── while1.c │ │ ├── compiler.spec.ts │ │ ├── test-assets │ │ │ ├── basic.c │ │ │ ├── call-by-ref.fluffos.c │ │ │ ├── fluffos-new.c │ │ │ ├── fluffos.c │ │ │ ├── fluffos.h │ │ │ ├── includes-test.c │ │ │ ├── includes-test.h │ │ │ ├── ldmud.c │ │ │ ├── ldmud.h │ │ │ ├── obj.c │ │ │ ├── parser-error.c │ │ │ ├── preproc.c │ │ │ ├── syntax-functions.fluffos.c │ │ │ └── syntax-switch.fluffos.c │ │ └── test-utils.ts │ ├── types.ts │ └── utils.ts ├── tsconfig.json └── tsconfig.lib.json ├── syntaxes ├── lpc.tmLanguage.json └── lpcdoc.injection.tmLanguage.json └── tsconfig.json /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=LPC 2 | *.h linguist-language=LPC 3 | *.js linguist-language=TypeScript 4 | **/*.json linguist-language=jsonc 5 | 6 | **/__snapshots__/**/* -diff linguist-generated=true -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | This project is a vscode language server and compiler for the LPC language. It is based on the TypeScript compiler. 2 | 3 | Github issues are used to track work items. 4 | 5 | We use npm for package management, and esbuild to build and bundle. Jest is used for tests. 6 | 7 | There are several .c and .h files in this project. Those contain `LPC` code, not `C`. 8 | -------------------------------------------------------------------------------- /.github/workflows/lpc-build.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | name: Build LPC 3 | 4 | jobs: 5 | lpc_build: 6 | runs-on: ubuntu-latest 7 | name: Build LPC Code 8 | steps: 9 | - name: Checkout repository 10 | uses: actions/checkout@master 11 | 12 | - name: Build 13 | id: build 14 | uses: jlchmura/lpc-build-action@main 15 | with: 16 | lpc-config: ${{ github.workspace }}/efuns/fluffos/lpc-config.json 17 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: ["main"] 9 | pull_request: 10 | branches: ["main"] 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | 16 | strategy: 17 | matrix: 18 | node-version: [18.x, 20.x] 19 | os: [ubuntu-latest, windows-latest, macos-latest] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: "npm" 29 | - run: npm ci 30 | - run: npm run compile --if-present 31 | - run: npm test 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create Github Release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' # Run when a version tag (e.g., v1.0.0) is pushed 6 | jobs: 7 | test: 8 | if: github.ref_type == 'tag' 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | node-version: [20.x] 13 | os: [ubuntu-latest, windows-latest, macos-latest] 14 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v3 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | cache: "npm" 23 | - run: npm ci 24 | - run: npm run compile --if-present 25 | - run: npm test 26 | build: 27 | needs: test 28 | runs-on: ubuntu-latest 29 | permissions: 30 | contents: write 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@master 34 | 35 | - name: Setup Node.js 36 | uses: actions/setup-node@v4 37 | with: 38 | node-version: 20 39 | 40 | - name: Install dependencies 41 | run: npm ci 42 | 43 | - name: Build 44 | run: npm run vsce:package 45 | 46 | - name: Upload Artifact 47 | uses: actions/upload-artifact@v4 48 | with: 49 | path: "lpc-*.vsix" 50 | 51 | - name: Create Release 52 | id: create_release 53 | uses: ncipollo/release-action@v1.14.0 54 | with: 55 | artifacts: "lpc-*.vsix" 56 | # bodyFile: "CHANGELOG.md" 57 | prerelease: false 58 | generateReleaseNotes: true 59 | 60 | - name: Publish to Visual Studio Marketplace 61 | uses: HaaLeo/publish-vscode-extension@v1 62 | with: 63 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 64 | registryUrl: https://marketplace.visualstudio.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | client/server 4 | .vscode-test 5 | .antlr 6 | grammar/test 7 | parser2 8 | test.c 9 | test*.c 10 | test*.h 11 | .DS_Store 12 | *.vsix 13 | coverage 14 | *.heapsnapshot 15 | vscode-profile-*.* 16 | tsconfig.tsbuildinfo 17 | isolate*.log 18 | lib/**/* 19 | !lib/package.json 20 | !lib/README.md 21 | launch.json -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | EfunsLDMud.ts 2 | server/src/compiler/**/*.ts 3 | server/src/compiler2/**/*.ts 4 | types.ts -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "client/node_modules": true, 4 | "client/out": true, 5 | "server/node_modules": true, 6 | "server/out": true, 7 | // "out": true, 8 | "node_modules": true 9 | }, 10 | "editor.formatOnSave": false, 11 | "editor.formatOnPaste": false, 12 | "[antlr]": { 13 | "editor.formatOnSave": false 14 | }, 15 | "[lpc]": { 16 | "editor.formatOnSave": false 17 | }, 18 | 19 | "typescript.preferences.autoImportFileExcludePatterns": [ 20 | "/**/compiler2/" 21 | ], 22 | "typescript.tsdk": "node_modules/typescript/lib", 23 | "cSpell.words": [ 24 | "efun", 25 | "sefun" 26 | ], 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "compile", 6 | "type": "npm", 7 | "script": "compile", 8 | "group": "build", 9 | "presentation": { 10 | "panel": "dedicated", 11 | "reveal": "never" 12 | }, 13 | "problemMatcher": ["$tsc"] 14 | }, 15 | { 16 | "label": "compile:bin", 17 | "type": "npm", 18 | "script": "compile:bin", 19 | "group": "build", 20 | "presentation": { 21 | "panel": "dedicated", 22 | "reveal": "never" 23 | }, 24 | "problemMatcher": ["$tsc"] 25 | }, 26 | { 27 | "label": "watch", 28 | "type": "npm", 29 | "script": "watch", 30 | "isBackground": true, 31 | "group": { 32 | "kind": "build", 33 | "isDefault": true 34 | }, 35 | "presentation": { 36 | "panel": "dedicated", 37 | "reveal": "never" 38 | }, 39 | "problemMatcher": ["$tsc-watch"] 40 | }, 41 | { 42 | "type": "npm", 43 | "script": "postinstall", 44 | "problemMatcher": [], 45 | "label": "npm: postinstall", 46 | "detail": "cd client && npm install && cd ../server && npm install && cd .." 47 | }, 48 | { 49 | "type": "npm", 50 | "script": "compile:parsefluff", 51 | "group": "build", 52 | "problemMatcher": [], 53 | "label": "compile:parsefluff", 54 | "detail": "tsc -b && esbuild server/src/parse-fluff-docs.ts --bundle --outdir=out/server/src --external:vscode --platform=node --format=cjs --sourcemap=external --sourcemap" 55 | }, 56 | { 57 | "type": "npm", 58 | "script": "compile:parseld", 59 | "group": "build", 60 | "problemMatcher": [], 61 | "label": "compile:parseld", 62 | "detail": "tsc -b && esbuild server/src/parse-ld-docs.ts --bundle --outdir=out/server/src --external:vscode --platform=node --format=cjs --sourcemap=external --sourcemap" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .github/** 3 | .git/** 4 | node_modules/** 5 | **/*.ts 6 | **/*.map 7 | .gitignore 8 | .prettierignore 9 | **/tsconfig.json 10 | **/tsconfig.base.json 11 | contributing.md 12 | .travis.yml 13 | out/**/* 14 | client/ 15 | server/ 16 | grammar/ 17 | test*.c 18 | test*.h 19 | efuns/ 20 | !out/server/src/cli/**.* 21 | !out/server/src/server.js 22 | !out/server/src/server.js.map 23 | !out/client/src/extension.js 24 | !out/client/src/extension.js.map 25 | !out/server/src/efuns/**/* 26 | !out/lib/**/* 27 | jest.config.ts 28 | tests/ 29 | coverage/ 30 | lpc-config.json 31 | *.heapsnapshot 32 | vscode-profile-*.* 33 | build*.mjs 34 | build*.js 35 | scripts/ 36 | lib/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 John Chmura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.lib.js: -------------------------------------------------------------------------------- 1 | const ts = require("typescript"); 2 | const esbuild = require("esbuild"); 3 | const path = require("path"); 4 | const { dependencies, peerDependencies } = require('./package.json'); 5 | const { serverDeps = dependencies, serverPeers = peerDependencies } = require('./server/package.json'); 6 | 7 | const external = Object.keys(dependencies) 8 | .concat(Object.keys(peerDependencies || [])) 9 | .concat(Object.keys(serverDeps || [])) 10 | .concat(Object.keys(serverPeers || [])); 11 | 12 | // LIB - CJS 13 | esbuild.build({ 14 | entryPoints: ['server/src/lpc/lpc.ts'], 15 | bundle: true, 16 | banner: { js: "// Copyright 2024 John L Chmura\n" }, 17 | outfile: 'out/lib/lpc.js', 18 | target: ["es2020"], 19 | external: Object.keys(dependencies).concat(Object.keys(peerDependencies || [])), 20 | packages: "external", 21 | sourcesContent: false, 22 | platform: 'node', 23 | format: 'cjs', 24 | sourcemap: 'linked', 25 | mainFields: ['module','main'], 26 | logLevel: 'warning', 27 | }) 28 | 29 | // CLI 30 | esbuild.build({ 31 | entryPoints: ['server/src/cli/lpc.ts'], 32 | bundle: true, 33 | banner: { js: "// Copyright 2024 John L Chmura\n" }, 34 | outfile: 'out/lib/cli.js', 35 | // outdir: 'out/lib', 36 | target: ["es2020"], 37 | external: Object.keys(dependencies).concat(Object.keys(peerDependencies || [])), 38 | platform: 'node', 39 | format: 'cjs', 40 | sourcemap: 'linked', 41 | mainFields: ['module','main'], 42 | logLevel: 'warning', 43 | treeShaking: true, 44 | minify: true 45 | }) 46 | 47 | // SERVER 48 | esbuild.build({ 49 | entryPoints: ['server/src/server.ts'], 50 | bundle: true, 51 | banner: { js: "// Copyright 2024 John L Chmura\n" }, 52 | outfile: 'out/lib/server.js', 53 | target: ["es2020"], 54 | external: Object.keys(dependencies).concat(Object.keys(peerDependencies || [])), 55 | platform: 'node', 56 | format: 'cjs', 57 | sourcemap: 'linked', 58 | mainFields: ['module','main'], 59 | logLevel: 'warning', 60 | treeShaking: true, 61 | minify: true 62 | }) 63 | -------------------------------------------------------------------------------- /build.mjs: -------------------------------------------------------------------------------- 1 | import * as esbuild from 'esbuild' 2 | 3 | await esbuild.build({ 4 | entryPoints: ['client/src/extension.ts','server/src/server.ts', 'server/src/cli/lpc.ts'], 5 | bundle: true, 6 | outdir: 'out', 7 | external: ['vscode'], 8 | platform: 'node', 9 | format: 'cjs', 10 | sourcemap: 'linked', 11 | // treeShaking: true, 12 | // minify: true, 13 | mainFields: ['module', 'main'], // needed for jsonc-parse until they fix https://github.com/microsoft/node-jsonc-parser/issues/57 14 | }); -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lpc-language-server-client", 3 | "description": "VSCode client for LPC language server", 4 | "author": "jlchmura", 5 | "license": "MIT", 6 | "version": "0.0.1", 7 | "publisher": "jlchmura", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/jlchmura/lpc-language-server" 11 | }, 12 | "engines": { 13 | "vscode": "^1.75.0" 14 | }, 15 | "dependencies": { 16 | "vscode-languageclient": "^8.1.0" 17 | }, 18 | "devDependencies": { 19 | "@types/vscode": "^1.75.1", 20 | "@vscode/test-electron": "^2.2.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /client/src/ProgressIndicator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on ANTLR4 code from Mike Lischke. 3 | * 4 | * Copyright (c) Mike Lischke. All rights reserved. 5 | * Licensed under the MIT License. See License.txt in the project root for license information. 6 | */ 7 | 8 | import { StatusBarAlignment, StatusBarItem, window } from "vscode"; 9 | 10 | export class ProgressIndicator { 11 | private static progressChars = 12 | "⠁⠃⠅⡁⢁⠡⠑⠉⠁⠃⠇⡃⢃⠣⠓⠋⠃⠃⠇⡇⢇⠧⠗⠏⠇⠇⠇⡇⣇⡧⡗⡏⡇⡇⡇⡇⣇⣧⣗⣏⣇⣇⣇⣇⣇⣧⣷⣯⣧⣧⣧⣧⣧⣧⣷⠧⠗⠏⠇⠇⠇⣿⣿⣿⣿⣿⣿⣿⣿"; 13 | 14 | private statusBarItem: StatusBarItem; 15 | private timer: ReturnType | null; 16 | private progress = 0; 17 | 18 | public driverType: string = ""; 19 | 20 | public constructor() { 21 | this.statusBarItem = window.createStatusBarItem( 22 | "lpc", 23 | StatusBarAlignment.Left, 24 | 1 25 | ); 26 | this.statusBarItem.name = "LPC Language Server"; 27 | this.setText(); 28 | } 29 | 30 | private setText() { 31 | this.statusBarItem.text = this.baseText(); 32 | this.statusBarItem.tooltip = 33 | "LPC Language Server - Driver Type: " + this.driverType; 34 | } 35 | 36 | public startAnimation(): void { 37 | this.statusBarItem.show(); 38 | if (!this.timer) { 39 | this.timer = setInterval(() => { 40 | const index = 41 | this.progress % ProgressIndicator.progressChars.length; 42 | this.statusBarItem.text = `${this.baseText()} ${ProgressIndicator.progressChars.charAt( 43 | index 44 | )}`; 45 | this.progress++; 46 | }, 50); 47 | } 48 | } 49 | 50 | public stopAnimation(): void { 51 | if (this.timer) { 52 | clearInterval(this.timer); 53 | this.timer = null; 54 | this.statusBarItem.text = this.baseText(); 55 | } 56 | } 57 | 58 | private baseText(): string { 59 | return `LPC [${this.driverType}]`; 60 | } 61 | 62 | public setDriverType(type: string) { 63 | this.driverType = type; 64 | this.setText(); 65 | } 66 | 67 | public show() { this.statusBarItem.show(); } 68 | public hide() { this.statusBarItem.hide(); } 69 | } 70 | -------------------------------------------------------------------------------- /client/src/configuration/configuration.node.ts: -------------------------------------------------------------------------------- 1 | import { BaseServiceConfigurationProvider } from "./configuration"; 2 | 3 | export class NodeServiceConfigurationProvider extends BaseServiceConfigurationProvider {} -------------------------------------------------------------------------------- /client/src/configuration/configuration.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export abstract class BaseServiceConfigurationProvider { 4 | public loadFromWorkspace(): LpcServiceConfiguration { 5 | const configuration = vscode.workspace.getConfiguration(); 6 | return { 7 | locale: this.readLocale(configuration), 8 | maxLpcServerMemory: this.readMaxLpcServerMemory(configuration), 9 | } 10 | } 11 | 12 | protected readLocale(configuration: vscode.WorkspaceConfiguration): string | null { 13 | const value = configuration.get('LPC.locale', 'auto'); 14 | return !value || value === 'auto' ? null : value; 15 | } 16 | 17 | protected readMaxLpcServerMemory(configuration: vscode.WorkspaceConfiguration): number { 18 | const defaultMaxMemory = 3072; 19 | const minimumMaxMemory = 128; 20 | const memoryInMB = configuration.get('LPC.languageServer.maxLpcServerMemory', defaultMaxMemory); 21 | if (!Number.isSafeInteger(memoryInMB)) { 22 | return defaultMaxMemory; 23 | } 24 | return Math.max(memoryInMB, minimumMaxMemory); 25 | } 26 | } 27 | 28 | export interface LpcServiceConfiguration { 29 | readonly locale: string | null; 30 | readonly maxLpcServerMemory: number; 31 | } -------------------------------------------------------------------------------- /client/src/configuration/languageDescription.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { basename } from 'path'; 7 | import * as vscode from 'vscode'; 8 | import * as languageIds from './languageIds'; 9 | 10 | export const enum DiagnosticLanguage { 11 | JavaScript, 12 | TypeScript 13 | } 14 | 15 | export const allDiagnosticLanguages = [DiagnosticLanguage.JavaScript, DiagnosticLanguage.TypeScript]; 16 | 17 | export interface LanguageDescription { 18 | readonly id: string; 19 | readonly diagnosticOwner: string; 20 | readonly diagnosticSource: string; 21 | readonly diagnosticLanguage: DiagnosticLanguage; 22 | readonly languageIds: readonly string[]; 23 | readonly configFilePattern?: RegExp; 24 | readonly isExternal?: boolean; 25 | readonly standardFileExtensions: readonly string[]; 26 | } 27 | 28 | export const standardLanguageDescriptions: LanguageDescription[] = [ 29 | { 30 | id: 'typescript', 31 | diagnosticOwner: 'typescript', 32 | diagnosticSource: 'ts', 33 | diagnosticLanguage: DiagnosticLanguage.TypeScript, 34 | languageIds: [languageIds.lpc], 35 | configFilePattern: /^lpc-config(\..*)?\.json$/i, 36 | standardFileExtensions: [ 37 | 'c', 38 | 'h', 39 | 'lpc' 40 | ], 41 | } 42 | ]; 43 | 44 | export function isLpcConfigFileName(fileName: string): boolean { 45 | return /^lpc-config\.(.+\.)?json$/i.test(basename(fileName)); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /client/src/configuration/languageIds.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | 8 | export const lpc = 'lpc'; 9 | export const javascript = 'javascript'; 10 | 11 | export const lpcLanguageModes = [ 12 | lpc 13 | ]; 14 | 15 | export function isSupportedLanguageMode(doc: vscode.TextDocument) { 16 | return vscode.languages.match([lpc], doc) > 0; 17 | } 18 | 19 | export function isLpcDocument(doc: vscode.TextDocument) { 20 | return vscode.languages.match([lpc], doc) > 0; 21 | } 22 | -------------------------------------------------------------------------------- /client/src/documentSelector.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | 8 | export interface DocumentSelector { 9 | /** 10 | * Selector for files which only require a basic syntax server. 11 | */ 12 | readonly syntax: readonly vscode.DocumentFilter[]; 13 | 14 | /** 15 | * Selector for files which require semantic server support. 16 | */ 17 | readonly semantic: readonly vscode.DocumentFilter[]; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/fileSchemes.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | import { isWeb } from './utils/platform'; 8 | 9 | export const file = 'file'; 10 | export const untitled = 'untitled'; 11 | export const git = 'git'; 12 | export const github = 'github'; 13 | export const azurerepos = 'azurerepos'; 14 | 15 | /** Live share scheme */ 16 | export const vsls = 'vsls'; 17 | export const walkThroughSnippet = 'walkThroughSnippet'; 18 | export const vscodeNotebookCell = 'vscode-notebook-cell'; 19 | export const officeScript = 'office-script'; 20 | export const chatCodeBlock = 'vscode-chat-code-block'; 21 | 22 | export function getSemanticSupportedSchemes() { 23 | if (isWeb() && vscode.workspace.workspaceFolders) { 24 | return vscode.workspace.workspaceFolders.map(folder => folder.uri.scheme); 25 | } 26 | 27 | return [ 28 | file, 29 | untitled, 30 | walkThroughSnippet, 31 | vscodeNotebookCell, 32 | chatCodeBlock, 33 | ]; 34 | } 35 | 36 | /** 37 | * File scheme for which JS/TS language feature should be disabled 38 | */ 39 | export const disabledSchemes = new Set([ 40 | git, 41 | vsls, 42 | github, 43 | azurerepos, 44 | ]); 45 | -------------------------------------------------------------------------------- /client/src/languageFeatures/utilities.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export function toOpenLpcFilePath(document: vscode.TextDocument): string | undefined { 4 | if (document.uri.scheme === 'file') { 5 | return document.uri.fsPath; 6 | } 7 | return undefined; 8 | } -------------------------------------------------------------------------------- /client/src/task/lpcConfigProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export interface LpcConfig { 4 | readonly uri: vscode.Uri; 5 | readonly fsPath: string; 6 | readonly posixPath: string; 7 | readonly workspaceFolder?: vscode.WorkspaceFolder; 8 | } 9 | 10 | export class LpcConfigProvider { 11 | public async getConfigsForWorkspace(token: vscode.CancellationToken): Promise> { 12 | if (!vscode.workspace.workspaceFolders) { 13 | return []; 14 | } 15 | 16 | const configs = new Map(); 17 | for (const config of await this.findConfigFiles(token)) { 18 | const root = vscode.workspace.getWorkspaceFolder(config); 19 | if (root) { 20 | configs.set(config.fsPath, { 21 | uri: config, 22 | fsPath: config.fsPath, 23 | posixPath: config.path, 24 | workspaceFolder: root 25 | }); 26 | } 27 | } 28 | return configs.values(); 29 | } 30 | 31 | private async findConfigFiles(token: vscode.CancellationToken): Promise { 32 | return await vscode.workspace.findFiles('**/lpc-config.json', '**/{node_modules,.*}/**', undefined, token); 33 | } 34 | } -------------------------------------------------------------------------------- /client/src/typeConverters.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import type * as Proto from './protocol/protocol'; 3 | 4 | export namespace Range { 5 | export const fromTextSpan = (span: Proto.TextSpan): vscode.Range => 6 | fromLocations(span.start, span.end); 7 | 8 | export const toTextSpan = (range: vscode.Range): Proto.TextSpan => ({ 9 | start: Position.toLocation(range.start), 10 | end: Position.toLocation(range.end) 11 | }); 12 | 13 | export const fromLocations = (start: Proto.Location, end: Proto.Location): vscode.Range => 14 | new vscode.Range( 15 | Math.max(0, start.line - 1), Math.max(start.offset - 1, 0), 16 | Math.max(0, end.line - 1), Math.max(0, end.offset - 1)); 17 | 18 | export const toFileRangeRequestArgs = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ 19 | file, 20 | startLine: range.start.line + 1, 21 | startOffset: range.start.character + 1, 22 | endLine: range.end.line + 1, 23 | endOffset: range.end.character + 1 24 | }); 25 | 26 | // export const toFormattingRequestArgs = (file: string, range: vscode.Range): Proto.FormatRequestArgs => ({ 27 | // file, 28 | // line: range.start.line + 1, 29 | // offset: range.start.character + 1, 30 | // endLine: range.end.line + 1, 31 | // endOffset: range.end.character + 1 32 | // }); 33 | } 34 | 35 | 36 | export namespace Position { 37 | export const fromLocation = (tslocation: Proto.Location): vscode.Position => 38 | new vscode.Position(tslocation.line - 1, tslocation.offset - 1); 39 | 40 | export const toLocation = (vsPosition: vscode.Position): Proto.Location => ({ 41 | line: vsPosition.line + 1, 42 | offset: vsPosition.character + 1, 43 | }); 44 | 45 | export const toFileLocationRequestArgs = (file: string, position: vscode.Position): Proto.FileLocationRequestArgs => ({ 46 | file, 47 | line: position.line + 1, 48 | offset: position.character + 1, 49 | }); 50 | } 51 | 52 | export namespace Location { 53 | export const fromTextSpan = (resource: vscode.Uri, tsTextSpan: Proto.TextSpan): vscode.Location => 54 | new vscode.Location(resource, Range.fromTextSpan(tsTextSpan)); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /client/src/utils/dispose.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | 8 | export function disposeAll(disposables: vscode.Disposable[]) { 9 | for (const disposable of disposables) { 10 | disposable.dispose(); 11 | } 12 | disposables.length = 0; 13 | } 14 | 15 | export interface IDisposable { 16 | dispose(): void; 17 | } 18 | 19 | export abstract class Disposable { 20 | private _isDisposed = false; 21 | 22 | protected _disposables: vscode.Disposable[] = []; 23 | 24 | public dispose(): any { 25 | if (this._isDisposed) { 26 | return; 27 | } 28 | this._isDisposed = true; 29 | disposeAll(this._disposables); 30 | } 31 | 32 | protected _register(value: T): T { 33 | if (this._isDisposed) { 34 | value.dispose(); 35 | } else { 36 | this._disposables.push(value); 37 | } 38 | return value; 39 | } 40 | 41 | protected get isDisposed() { 42 | return this._isDisposed; 43 | } 44 | } 45 | 46 | export class DisposableStore extends Disposable { 47 | 48 | public add(disposable: T): T { 49 | this._register(disposable); 50 | 51 | return disposable; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /client/src/utils/platform.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import * as vscode from 'vscode'; 7 | 8 | export function isWeb(): boolean { 9 | return 'navigator' in globalThis && vscode.env.uiKind === vscode.UIKind.Web; 10 | } 11 | 12 | export function isWebAndHasSharedArrayBuffers(): boolean { 13 | return isWeb() && (globalThis as any)['crossOriginIsolated']; 14 | } 15 | -------------------------------------------------------------------------------- /client/src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export const wait = (ms: number) => new Promise(resolve => setTimeout(() => resolve(), ms)); 4 | 5 | export function coalesce(array: ReadonlyArray): T[] { 6 | return array.filter((e): e is T => !!e); 7 | } 8 | 9 | export async function exists(resource: vscode.Uri): Promise { 10 | try { 11 | const stat = await vscode.workspace.fs.stat(resource); 12 | // stat.type is an enum flag 13 | return !!(stat.type & vscode.FileType.File); 14 | } catch { 15 | return false; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "target": "es2020", 5 | "moduleResolution": "node", 6 | "lib": ["es2020"], 7 | "outDir": "out", 8 | "rootDir": "src", 9 | "sourceMap": true 10 | }, 11 | "include": ["src"], 12 | "exclude": ["node_modules", ".vscode-test"] 13 | } 14 | -------------------------------------------------------------------------------- /config-changes.md: -------------------------------------------------------------------------------- 1 | # LPC Config v2 Breaking Changes 2 | 3 | The rewrite of the language server for version 2 necessitated some breaking config file changes. 4 | This document outlines how to migrate your `lpc-config.json` file. 5 | 6 | ### The following config options were renamed: 7 | 8 | - `include` is now `libInclude` 9 | - `files` is now `libFiles` 10 | - `diagnostics` should now be set to either `"on"` or `"off"` 11 | - `mudlibDir` was removed, see below. 12 | 13 | ### Adding files to your project (or, what happened to mudlibDir?) 14 | 15 | To place your lpc-config file in a folder other than your lib's root directory, you need to tell it how to locate lib files. 16 | The `include` setting tells the compiler where those files are located and can be either a relative path (from the location of your config file) or a 17 | disk rooted path. The first entry in this array will be used as your "lib root" folder. 18 | 19 | Example: 20 | 21 | For example, let's say your project is structured thus: 22 | 23 | ``` 24 | MyProj 25 | |- settings 26 | | |- lpc-config.json 27 | |- lib 28 | | |- std 29 | | | |- simul_efun.c 30 | | |- rooms 31 | | | |- entrance.c 32 | | |- admin 33 | ``` 34 | 35 | In this case, your config file should read: 36 | ```json 37 | { 38 | "include": ["../lib"], 39 | ... 40 | } 41 | ``` -------------------------------------------------------------------------------- /efuns/fluffos/async.h: -------------------------------------------------------------------------------- 1 | // async.h 2 | 3 | /** 4 | * async_write() - appends a string to a file then executes a callback 5 | * 6 | * Append the string 'str' into the file 'file'. If flag is 1, write_file 7 | * overwrites instead of appending. 8 | * 9 | * Unlike write_file, which returns 0 for failure or 1 for success, this efun 10 | * will return -1 for failure and 0 for success to the callback. 11 | * 12 | * The callback should follow this format: 13 | * 14 | * function (int res) { 15 | * // -1 for failure 16 | * // 0 for success 17 | * } 18 | * 19 | */ 20 | void async_write( string file, string str, int flag, function callback ); 21 | 22 | /** 23 | * async_read() - read a file into a string then executes a callback 24 | * 25 | * Read a line of text from a file into a string. Normally, read_file 26 | * takes a second and third arguments for start_line and number_of_lines to 27 | * read, but async_read will return the entire file to the callback. 28 | * 29 | * The callback should follow this format: 30 | * 31 | * function(mixed res) { 32 | * // -1 for file not read 33 | * // string file contents otherwise 34 | * } 35 | * 36 | */ 37 | void async_read( string file, function callback ); 38 | 39 | /** 40 | * async_getdir() - returns information pertaining to a filesystem directory 41 | * 42 | * If 'dir' is a filename ('*' and '?' wildcards are supported), an array 43 | * of strings is returned to the callback containing all filenames that match 44 | * the specification. If 'dir' is a directory name (ending with a slash--ie: 45 | * "/u/", "/adm/", etc), all filenames in that directory are returned. 46 | * 47 | * Unlike the get_dir routine, this efun does not take an integer second 48 | * argument to specify more information (filename, filesize, last touched). 49 | * 50 | * The callback should follow this format: 51 | * 52 | * function(mixed res) { 53 | * // 0 when directory doesn't exist 54 | * // empty array when no matching files exist 55 | * // array of matching filenames 56 | * } 57 | * 58 | */ 59 | void async_getdir( string dir, function callback ); 60 | 61 | /** 62 | * async_db_exec() - executes an sql statement then executes a callback 63 | * 64 | * This function will execute the passed sql statement for the given data‐ 65 | * base handle. 66 | * 67 | * Returns the database handle to the callback function provided. 68 | * 69 | * The callback should follow this format: 70 | * 71 | * ```c 72 | * async_db_exec( 73 | * handle, 74 | * sql_query, 75 | * function (int rows) { // number of matched rows 76 | * mixed *results = db_fetch(handle, 1); 77 | * db_close(handle); 78 | * } 79 | * ); 80 | * ``` 81 | * 82 | */ 83 | void async_db_exec( int handle, string sql_query, function callback ); 84 | 85 | -------------------------------------------------------------------------------- /efuns/fluffos/buffers.h: -------------------------------------------------------------------------------- 1 | // buffers.h 2 | 3 | /** 4 | * write_buffer() - write a buffer to a file, or read into a buffer from a 5 | source 6 | * 7 | * If 'dest' is a file, then 'source' must be an int (and will be written 8 | * to the file in network-byte-order), a buffer, or a string, and 'source' 9 | * will be written to the file 'dest' starting at byte # 'start'. 10 | * 11 | * If 'dest' is a buffer, then 'source' will be written into the buffer 12 | * starting at byte # 'start' in the buffer. If 'source' is an int, it 13 | * will be written in network-byte-order. 14 | * 15 | */ 16 | int write_buffer( string | buffer dest, 17 | int start, 18 | mixed source ); 19 | 20 | /** 21 | * read_buffer() - read from a file and return a buffer, or return part of 22 | a buffer as a string 23 | * 24 | * If 'src' is a string (filename), then the filename will be read, start‐ 25 | * ing at byte # 'start', for 'len' bytes, and returned as a buffer. If 26 | * neither argument is given, the entire file is read. 27 | * 28 | * If 'src' is a buffer, then characters are read from the buffer begin‐ 29 | * ning at byte # 'start' in the buffer, and for 'len' # of bytes, and 30 | * returned as a string. 31 | * 32 | * Note that the maximum number of bytes you can read from a file and into 33 | * a buffer is controlled via the 'maximum byte transfer' parameter in the 34 | * runtime config file. 35 | * 36 | */ 37 | string | buffer read_buffer( string | buffer src, 38 | int start, 39 | int len ); 40 | 41 | /** 42 | * crc32() - compute the cycle redundancy code for a buffer or string 43 | * 44 | * Computes and returns the CRC-32 code for the given buffer or string, 'x'. 45 | * 46 | */ 47 | int crc32( buffer | string x ); 48 | 49 | /** 50 | * bufferp() - identifies whether a given variable is a buffer 51 | * 52 | * Return 1 if 'arg' is a buffer value and zero (0) otherwise. 53 | * 54 | * int is_buffer = bufferp( allocate_buffer(10) ); // 1 55 | * int is_buffer = bufferp( "Foo" ); // 0 56 | * 57 | */ 58 | int bufferp( mixed arg ); 59 | 60 | /** 61 | * buffer_transcode() - transcode a buffer from one encoding to another 62 | * 63 | * Transcode given buffer from encoding 'from_encoding' to encoding 64 | * 'to_encoding'. 65 | * 66 | */ 67 | buffer buffer_transcode(buffer src, 68 | string from_encoding, 69 | string to_encoding); 70 | 71 | /** 72 | * allocate_buffer() - allocate a buffer 73 | * 74 | * Allocate a buffer of elements. The number of elements must be 75 | * >= 0 and not bigger than a system maximum (usually ~10000). All ele‐ 76 | * ments are initialized to 0. 77 | * 78 | */ 79 | buffer allocate_buffer( int size ); 80 | 81 | -------------------------------------------------------------------------------- /efuns/fluffos/ed.h: -------------------------------------------------------------------------------- 1 | // ed.h 2 | 3 | /** 4 | * query_ed_mode() - find out the status of the current ed session 5 | * 6 | * Finds the status of the ed session for the current object, if one 7 | * exists. It returns: 8 | * 9 | * 0 - the current object is at a normal ed prompt (':') 10 | * 11 | * -1 - the current object isn't in ed 12 | * 13 | * -2 - the current object is at the more prompt in the middle of help 14 | * 15 | * >0 - the object is at a prompt for a line. The number is the line 16 | * number. 17 | * 18 | */ 19 | int query_ed_mode(); 20 | 21 | /** 22 | * ed_start() - start an ed session 23 | * 24 | * This efun is available only if __OLD_ED__ is not defined. 25 | * 26 | * The internal editor is started, optionally loading 'file' for editing. 27 | * The resulting output is returned. The editor session remains active, 28 | * and further calls to ed_cmd() can be used to send commands to it. 29 | * 30 | * If restricted is 1, the commands that change which file is being edited 31 | * will be disabled. 32 | * 33 | * Only one ed session can be active per object at a time. 34 | * 35 | */ 36 | string ed_start(void|string file, void|int restricted); 37 | 38 | /** 39 | * ed_cmd() - send a command to an ed session 40 | * 41 | * This efun is available only if __OLD_ED__ is not defined. 42 | * 43 | * The command 'cmd' is sent to the active ed session, and the resulting 44 | * output is returned. 45 | * 46 | */ 47 | string ed_cmd(string cmd); 48 | 49 | -------------------------------------------------------------------------------- /efuns/fluffos/efuns.fluffos.h: -------------------------------------------------------------------------------- 1 | /** These objects must be here - they are used by the type checker for various non-primitive types */ 2 | object __LS__Array; 3 | object __LS__Mapping; 4 | object __LS__Object; 5 | object __LS__Function; 6 | object __LS__CallableFunction; 7 | object __LS__NewableFunction; 8 | object __LS__Int; 9 | object __LS__ReadonlyArray; 10 | object __LS__String; 11 | object __LS__Closure; 12 | 13 | // Driver Provided Defines 14 | // These are made available to each sourcefile 15 | #define MUDOS 1 16 | #define FLUFFOS 1 17 | #define __GET_CHAR_IS_BUFFERED__ 1 18 | #define __PORT__ 1 19 | #define __VERSION__ "1.0" 20 | #define __ARCH__ "x86_64" 21 | #define __COMPILER__ "gcc" 22 | #define __CXXFLAGS__ "linux" 23 | #define MUD_NAME "FluffOS" 24 | 25 | #define SIZEOFINT 4 26 | #define MAX_INT 2147483647 /* the largest integer number */ 27 | #define MIN_INT -2147483648 /* the smallest integer number */ 28 | #define MAX_FLOAT 1.0e+20 /* the largest (positive) float number */ 29 | #define MIN_FLOAT 0.00000 /* the smallest (positive) float number */ 30 | #define __LARGEST_PRINTABLE_STRING__ 8192 31 | #define __CACHE_STATS__ 1 32 | #define __STRING_STATS__ 1 33 | #define __ARRAY_STATS__ 1 34 | #define __CLASS_STATS__ 1 35 | #define __CALLOUT_HANDLES__ 1 36 | #define __ARGUMENTS_IN_TRACEBACK__ 1 37 | #define __LOCALS_IN_TRACEBACK__ 1 38 | #define __DEBUG_MACRO__ 1 39 | 40 | /* 41 | * efun definitions 42 | * 43 | * The doc comments in the FluffOS efun files were created 44 | * from the FluffOS source code. 45 | * https://github.com/fluffos/fluffos/tree/master/docs 46 | * 47 | * See the https://github.com/fluffos/fluffos/blob/master/Copyright 48 | * for license/copyright info. 49 | */ 50 | 51 | #include "arrays.h" 52 | #include "async.h" 53 | #include "buffers.h" 54 | #include "calls.h" 55 | #include "contrib.h" 56 | #include "db.h" 57 | #include "ed.h" 58 | #include "external.h" 59 | #include "filesystem.h" 60 | #include "floats.h" 61 | #include "functions.h" 62 | #include "general.h" 63 | #include "interactive.h" 64 | #include "internals.h" 65 | #include "mappings.h" 66 | #include "misc.h" 67 | #include "mudlib.h" 68 | #include "numbers.h" 69 | #include "objects.h" 70 | #include "parsing.h" 71 | #include "pcre.h" 72 | #include "sockets.h" 73 | #include "strings.h" 74 | #include "system.h" 75 | 76 | -------------------------------------------------------------------------------- /efuns/fluffos/external.h: -------------------------------------------------------------------------------- 1 | // external.h 2 | 3 | /** 4 | * external_start() - execute a shell command external to the driver 5 | * 6 | * Execute a shell command external to the driver. 7 | * 8 | * Commands that you would like to execute must be added to the runtime config. 9 | * The enumerated commands may then be invoked by their number as the first 10 | * argument to external_start `external_index`. 11 | * 12 | * This function returns the socket number which you should record for later 13 | * processing of the results from the external command. 14 | * 15 | * `args` - An array of the arguments passed to the external command. 16 | * `read_call_back` - As data becomes available, this function will be called 17 | * with a string containing that data. 18 | * `write_call_back` - I am not 100% sure what would be written to the external 19 | * command, but, this is a required parameter. 20 | * `close_call_back` - When the socket closes, this function is called. 21 | * 22 | * This is a very basic example using the information provided in this document 23 | * 24 | */ 25 | int external_start(int external_index, 26 | string *args, 27 | string|function read_call_back, 28 | string|function write_call_back, 29 | string|function close_call_back); 30 | 31 | -------------------------------------------------------------------------------- /efuns/fluffos/lpc-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "driver": { 3 | "type": "fluffos" 4 | }, 5 | "include": ["./"], 6 | "compilerOptions": { 7 | "noLib": true 8 | }, 9 | "diagnostics": "off" 10 | } 11 | -------------------------------------------------------------------------------- /efuns/fluffos/misc.h: -------------------------------------------------------------------------------- 1 | // test_bit.md.h 2 | 3 | /** 4 | * test_bit 5 | * set_bit() - set a bit in a bitstring 6 | * 7 | * Return 0 or 1 of bit 'n' was set in string 'str'. 8 | * 9 | */ 10 | int test_bit( string str, int n ); 11 | 12 | // test_load.md.h 13 | 14 | /** 15 | * test_load 16 | * test_load - test if a file is loadable 17 | * 18 | * Tests if a file is loadable. Will return 1 if a file is loadable, 19 | otherwise 0. If a file attempting to be loaded contains errors, 20 | they will be reported, in which case, you may need to wrap the 21 | function call in a catch statement to retrieve the 0 result. 22 | * 23 | */ 24 | int test_load( string filename ); 25 | 26 | 27 | /** 28 | * set_notify_destruct() - et the object to be notified when it is destructed 29 | * @param flag If the flag is set to 1, the object will 30 | * receive a call to the function on_destruct() when it is destructed. If the 31 | * flag is set to 0, the object will not receive this notification. 32 | * @details 33 | * Toggles a flag in an object that determines whether or not it will be 34 | * notified when it is destructed. If the flag is set to 1, the object will 35 | * receive a call to the function on_destruct() when it is destructed. If the 36 | * flag is set to 0, the object will not receive this notification. 37 | * Objects do not receive this notification by default. To receive the call to 38 | * on_destruct(), the object must call set_notify_destruct(1) at some point 39 | * during its lifetime. 40 | * The set_notify_destruct() efun may only be called from within the object 41 | * that would like to receive the notification. 42 | */ 43 | void set_notify_destruct(int flag); -------------------------------------------------------------------------------- /efuns/fluffos/numbers.h: -------------------------------------------------------------------------------- 1 | // numbers.h 2 | 3 | /** 4 | * to_float - convert an int to a float 5 | * 6 | * The to_float() call returns the number of type 'float' that is equiva‐ 7 | * lent to the int 'i'. 8 | * 9 | */ 10 | float to_float(int i); 11 | float to_float(string i); 12 | 13 | /** 14 | * secure_random() - return a pseudo-random number, this should be 15 | unpredictable, but maybe slightly slow. 16 | * 17 | * Return a cryptographically secure random number from the range [0 .. (n -1)] (inclusive). 18 | * 19 | * On Linux & OSX, this function explicitly use randomness from /dev/urandom, 20 | * on windows it is implementation defined. 21 | * 22 | */ 23 | int secure_random( int n ); 24 | 25 | /** 26 | * random() - return a pseudo-random number, this is suitable for general 27 | simulation, but may be predictable. 28 | * 29 | * Return a pseudo-random number from the range [0 .. (n -1)] (inclusive). 30 | * 31 | */ 32 | int random( int n ); 33 | 34 | /** 35 | * intp() - determine whether or not a given variable is an integer 36 | * 37 | * Return 1 if 'arg' is an integer number and zero (0) otherwise. 38 | * 39 | */ 40 | int intp( mixed arg ); 41 | 42 | -------------------------------------------------------------------------------- /efuns/fluffos/pcre.h: -------------------------------------------------------------------------------- 1 | // pcre.h 2 | 3 | /** 4 | * pcre_version() - returns the version of the compiled PCRE library used 5 | * 6 | * returns the version of the compiled PCRE library used 7 | * 8 | */ 9 | string pcre_version(void); 10 | 11 | /** 12 | * pcre_replace_callback() - string replace uses a callback to get the replace string 13 | * 14 | * returns a string where all captured groups have been replaced by the return 15 | * value of function pointer fun or function fun in object ob. (called with the 16 | * matched string and match number, starting with 0) 17 | * 18 | */ 19 | string pcre_replace_callback(string input, string pattern, string|function, mixed *args...); 20 | 21 | /** 22 | * pcre_replace() 23 | * 24 | * returns a string where all captured groups have been replaced by the 25 | * elements of the replacement array. Number of subgroups and the size of the 26 | * replacement array must match. 27 | * 28 | */ 29 | string pcre_replace(string input, string pattern, string *replacments); 30 | 31 | /** 32 | * pcre_match_all() - find all matches 33 | * 34 | * Similiar to php preg_match_all, this EFUN returns a array of string arrays, 35 | * containing all matches and captured groups. 36 | * 37 | */ 38 | mixed pcre_match_all(string input, string pattern); 39 | 40 | /** 41 | * pcre_match() - regular expression handler 42 | * 43 | * analog with regexp efun for backwards compatibility reasons but utilizing 44 | * the PCRE library. 45 | * 46 | */ 47 | mixed pcre_match(string|string *lines, string pattern, void|int flag); 48 | 49 | /** 50 | * pcre_extract() - extract matching parts 51 | * 52 | * returns an array of captured groups specified in pattern. 53 | * 54 | */ 55 | string *pcre_extract(string input, string pattern); 56 | 57 | /** 58 | * pcre_cache() - return content of the pcre cache 59 | * 60 | * returns content of the pcre cache (not all that useful). 61 | * 62 | */ 63 | mapping pcre_cache(void); 64 | 65 | /** 66 | * pcre_assoc() - A regular pattern substring extractor 67 | * 68 | * analog with reg_assoc efun for backwards compatibility reasons but utilizing 69 | * the PCRE library. 70 | * 71 | */ 72 | varargs mixed *pcre_assoc(string input, string *patterns, 73 | mixed *token_aray, 74 | mixed default_value); 75 | 76 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/async.zh-cn.h: -------------------------------------------------------------------------------- 1 | // async.h 2 | 3 | /** 4 | * async_write() - 将字符串追加到文件中,然后执行回调 5 | * 6 | * 将字符串 'str' 追加到文件 'file' 中。如果标志为 1,write_file 7 | * 将覆盖而不是追加。 8 | * 9 | * 与 write_file 不同,它返回 0 表示失败或 1 表示成功,此 efun 10 | * 将返回 -1 表示失败,0 表示成功给回调函数。 11 | * 12 | * 回调函数应该遵循以下格式: 13 | * 14 | * function (int res) { 15 | * // -1 表示失败 16 | * // 0 表示成功 17 | * } 18 | * 19 | */ 20 | void async_write( string file, string str, int flag, function callback ); 21 | 22 | /** 23 | * async_read() - 将文件读入字符串中,然后执行回调 24 | * 25 | * 从文件中读取一行文本到字符串中。通常,read_file 26 | * 需要第二个和第三个参数指定起始行和要读取的行数,但 async_read 将返回 27 | * 整个文件内容给回调函数。 28 | * 29 | * 回调函数应该遵循以下格式: 30 | * 31 | * function(mixed res) { 32 | * // -1 表示文件未读 33 | * // 其他情况返回字符串的文件内容 34 | * } 35 | * 36 | */ 37 | void async_read( string file, function callback ); 38 | 39 | /** 40 | * async_getdir() - 返回与文件系统目录相关的信息 41 | * 42 | * 如果 'dir' 是文件名(支持 '*' 和 '?' 通配符),返回一个字符串数组 43 | * 到回调函数,其中包含所有匹配的文件名。如果 'dir' 是目录名(以斜杠结尾--即: 44 | * "/u/", "/adm/", 等),将返回该目录中的所有文件名。 45 | * 46 | * 与 get_dir 例程不同,此 efun 不需要一个整数第二个 47 | * 参数来指定更多信息(文件名、文件大小、最后修改时间)。 48 | * 49 | * 回调函数应该遵循以下格式: 50 | * 51 | * function(mixed res) { 52 | * // 0 表示目录不存在 53 | * // 空数组表示没有匹配的文件存在 54 | * // 匹配文件名的数组 55 | * } 56 | * 57 | */ 58 | void async_getdir( string dir, function callback ); 59 | 60 | /** 61 | * async_db_exec() - 执行 SQL 语句然后执行回调 62 | * 63 | * 此函数将针对给定的数据‐库句柄执行传递的 SQL 语句。 64 | * 65 | * 返回数据库句柄给提供的回调函数。 66 | * 67 | * 回调函数应该遵循以下格式: 68 | * 69 | * ```c 70 | * async_db_exec( 71 | * handle, 72 | * sql_query, 73 | * function (int rows) { // 匹配的行数 74 | * mixed *results = db_fetch(handle, 1); 75 | * db_close(handle); 76 | * } 77 | * ); 78 | * ``` 79 | * 80 | */ 81 | void async_db_exec( int handle, string sql_query, function callback ); 82 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/buffers.zh-cn.h: -------------------------------------------------------------------------------- 1 | // buffers.h 2 | 3 | /** 4 | * write_buffer() - 将一个缓冲区写入文件,或从源读取到缓冲区 5 | * 6 | * 如果 'dest' 是一个文件,则 'source' 必须是一个整数(并将以网络字节序写入文件)、 7 | * 一个缓冲区或一个字符串,'source' 将从字节 # 'start' 开始写入文件 'dest'。 8 | * 9 | * 如果 'dest' 是一个缓冲区,则 'source' 将从字节 # 'start' 开始写入该缓冲区。 10 | * 如果 'source' 是一个整数,则将以网络字节序写入。 11 | * 12 | */ 13 | int write_buffer( string | buffer dest, 14 | int start, 15 | mixed source ); 16 | 17 | /** 18 | * read_buffer() - 从文件中读取并返回一个缓冲区,或将缓冲区的一部分作为字符串返回 19 | * 20 | * 如果 'src' 是一个字符串(文件名),则将从字节 # 'start' 开始读取文件,读取 'len' 字节, 21 | * 并作为缓冲区返回。如果没有提供任何参数,则读取整个文件。 22 | * 23 | * 如果 'src' 是一个缓冲区,则从字节 # 'start' 开始,从缓冲区中读取字符,并读取 'len' 字节, 24 | * 并作为字符串返回。 25 | * 26 | * 请注意,从文件中读取到缓冲区的最大字节数是通过运行时配置文件中的 'maximum byte transfer' 参数控制的。 27 | * 28 | */ 29 | string | buffer read_buffer( string | buffer src, 30 | int start, 31 | int len ); 32 | 33 | /** 34 | * crc32() - 计算缓冲区或字符串的循环冗余码 35 | * 36 | * 计算并返回给定缓冲区或字符串 'x' 的 CRC-32 码。 37 | * 38 | */ 39 | int crc32( buffer | string x ); 40 | 41 | /** 42 | * bufferp() - 确定给定变量是否是一个缓冲区 43 | * 44 | * 如果 'arg' 是一个缓冲区值,则返回 1,否则返回零 (0)。 45 | * 46 | * int is_buffer = bufferp( allocate_buffer(10) ); // 1 47 | * int is_buffer = bufferp( "Foo" ); // 0 48 | * 49 | */ 50 | int bufferp( mixed arg ); 51 | 52 | /** 53 | * buffer_transcode() - 将缓冲区从一种编码转码到另一种编码 54 | * 55 | * 将给定的缓冲区从编码 'from_encoding' 转码到编码 'to_encoding'。 56 | * 57 | */ 58 | buffer buffer_transcode(buffer src, 59 | string from_encoding, 60 | string to_encoding); 61 | 62 | /** 63 | * allocate_buffer() - 分配一个缓冲区 64 | * 65 | * 分配一个 元素的缓冲区。元素的数量必须 >= 0,并且不大于系统最大值(通常约为10000)。 66 | * 所有元素都初始化为 0。 67 | * 68 | */ 69 | buffer allocate_buffer( int size ); 70 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/db.zh-cn.h: -------------------------------------------------------------------------------- 1 | // db.h 2 | 3 | /** 4 | * db_status() - 返回包状态 5 | * 6 | * 返回描述当前数据库包状态的字符串。 7 | * 8 | */ 9 | string db_status( void ); 10 | 11 | /** 12 | * db_rollback() - 回滚上一个事务 13 | * 14 | * 对于事务性数据库,这将回滚最后一组操作。 15 | * 16 | * 成功时返回1,否则返回0。 17 | * 18 | */ 19 | int db_rollback( int ); 20 | 21 | /** 22 | * db_fetch() - 获取结果集 23 | * 24 | * 获取给定行的最后执行的SQL结果集,使用传递的数据库句柄。 25 | * 26 | * 成功时返回命名行的列数组,否则返回错误字符串。 27 | * 28 | * string *res; 29 | * mixed rows; 30 | * int dbconn, i; 31 | * 32 | * dbconn = db_connect("db.server", "db_mud"); 33 | * if(dbconn < 1) 34 | * return 0; 35 | * rows = db_exec(dbconn, "SELECT player_name, exp FROM t_player"); 36 | * if(!rows) 37 | * write("没有返回行。"); 38 | * else 39 | * if(stringp(rows)) /* 错误 *\/ 40 | * write(rows); 41 | * else 42 | * for(i = 1; i <= rows; i++) 43 | * { 44 | * res = db_fetch(dbconn, i); 45 | * write(res[0]); 46 | * write(res[1]); 47 | * } 48 | * 49 | * db_close(dbconn); 50 | * 51 | */ 52 | mixed *db_fetch( int handle, int row ); 53 | 54 | /** 55 | * db_exec() - 执行SQL语句 56 | * 57 | * 此函数将为给定的数据库句柄执行传递的SQL语句。 58 | * 59 | * 成功时返回结果集中行的数量,否则返回错误字符串。 60 | * 61 | */ 62 | mixed db_exec( int handle, string sql_query ); 63 | 64 | /** 65 | * db_connect() - 关闭数据库连接 66 | * 67 | * 在给定主机上创建与数据库db的新连接。连接使用给定用户或编译时值作为登录ID。类型可以用于选择数据库服务器的类型。有效值取决于编译时设置,应通过mudlib中的相应头文件提供。 68 | * 69 | * 成功时返回新连接的句柄,否则返回0。 70 | * 71 | * 驱动程序将调用主对象的valid_database函数以检索此数据库的密码(字符串)或批准(正整数)。 72 | * 73 | * FlufFOS支持MYSQL、SQLITE3和PostgreSQL。 74 | * 75 | * 编译驱动程序时,需要传递-DPACKAGE_DB=ON和 76 | * -DPACKAGE_DB_MYSQL=X或 77 | * -DPACKAGE_DB_SQLITE=X或 78 | * -DPACKAGE_DB_POSTGRESQL=X 79 | * 同时还应传递-DPACKAGE_DB_DEFAULT_DB=X,该值应为上述其中一个。如果某个值为空字符串,则驱动程序对该数据库的支持将被禁用。 80 | * 81 | * 这里的X代表表示db_connect()中“类型”参数的整数。 82 | * 83 | * 驱动程序为lib提供以下预定义常量以供数据库类型使用。 84 | * 85 | * __USE_MYSQL__ 是-DPACKAGE_DB_MYSQL=的值,默认值为1 86 | * __USE_SQLITE3__ 是-DPACKAGE_DB_SQLITE=的值,默认未定义。 87 | * __USE_POSTGRE__ 是-DPACKAGE_DB_POSTGRESQL=的值,默认未定义。 88 | * __DEFAULT_DB__ 是-DPACKAGE_DB_DEFAULT_DB=的值,默认值为1 89 | * 90 | */ 91 | int db_connect( string host, string db ); 92 | int db_connect( string host, string db, string user ); 93 | int db_connect( string host, string db, string user, int type ); 94 | 95 | /** 96 | * db_commit() - 提交上一个事务 97 | * 98 | * 对于事务性数据库,这将提交最后一组操作。 99 | * 100 | * 成功时返回1,否则返回0。 101 | * 102 | */ 103 | int db_commit(int handle ); 104 | 105 | /** 106 | * db_close() - 关闭数据库连接 107 | * 108 | * 关闭由给定句柄表示的数据库连接。 109 | * 110 | * 成功时返回1,否则返回0。 111 | * 112 | */ 113 | int db_close( int handle ); 114 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/ed.zh-cn.h: -------------------------------------------------------------------------------- 1 | // ed.h 2 | 3 | /** 4 | * query_ed_mode() - 查询当前编辑会话的状态 5 | * 6 | * 找出当前对象的编辑会话状态(如果存在)。返回值为: 7 | * 8 | * 0 - 当前对象处于正常的编辑提示(':') 9 | * 10 | * -1 - 当前对象不在编辑状态 11 | * 12 | * -2 - 当前对象在帮助中处于中间的更多提示 13 | * 14 | * >0 - 当前对象处于处理某一行的提示。数字表示行号。 15 | * 16 | */ 17 | int query_ed_mode(); 18 | 19 | /** 20 | * ed_start() - 开始一个编辑会话 21 | * 22 | * 本函数仅在未定义 __OLD_ED__ 时可用。 23 | * 24 | * 内部编辑器启动, optionally 加载 'file' 进行编辑。 25 | * 返回结果输出。编辑会话保持活跃,可以进一步调用 ed_cmd() 发送命令。 26 | * 27 | * 如果 restricted 为1,则将禁用更改正在编辑的文件的命令。 28 | * 29 | * 每个对象一次只能有一个编辑会话处于活跃状态。 30 | * 31 | */ 32 | string ed_start(void|string file, void|int restricted); 33 | 34 | /** 35 | * ed_cmd() - 向编辑会话发送命令 36 | * 37 | * 本函数仅在未定义 __OLD_ED__ 时可用。 38 | * 39 | * 命令 'cmd' 被发送到活跃的编辑会话,返回相应的输出。 40 | * 41 | */ 42 | string ed_cmd(string cmd); 43 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/efuns.fluffos.h: -------------------------------------------------------------------------------- 1 | /** These objects must be here - they are used by the type checker for various non-primitive types */ 2 | object __LS__Array; 3 | object __LS__Mapping; 4 | object __LS__Object; 5 | object __LS__Function; 6 | object __LS__CallableFunction; 7 | object __LS__NewableFunction; 8 | object __LS__Int; 9 | object __LS__ReadonlyArray; 10 | object __LS__String; 11 | object __LS__Closure; 12 | 13 | // Driver Provided Defines 14 | // These are made available to each sourcefile 15 | #define MUDOS 1 16 | #define FLUFFOS 1 17 | #define __GET_CHAR_IS_BUFFERED__ 1 18 | #define __MAX_READ_FILE_SIZE__ 1000000 19 | #define __PORT__ 1 20 | #define __VERSION__ "1.0" 21 | #define __ARCH__ "x86_64" 22 | #define __COMPILER__ "gcc" 23 | #define __CXXFLAGS__ "linux" 24 | #define MUD_NAME "FluffOS" 25 | 26 | #define SIZEOFINT 4 27 | #define MAX_INT 2147483647 /* the largest integer number */ 28 | #define MIN_INT -2147483648 /* the smallest integer number */ 29 | #define MAX_FLOAT 1.0e+20 /* the largest (positive) float number */ 30 | #define MIN_FLOAT 0.00000 /* the smallest (positive) float number */ 31 | #define __LARGEST_PRINTABLE_STRING__ 8192 32 | #define __CACHE_STATS__ 1 33 | #define __STRING_STATS__ 1 34 | #define __ARRAY_STATS__ 1 35 | #define __CLASS_STATS__ 1 36 | #define __CALLOUT_HANDLES__ 1 37 | #define __ARGUMENTS_IN_TRACEBACK__ 1 38 | #define __LOCALS_IN_TRACEBACK__ 1 39 | #define __DEBUG_MACRO__ 1 40 | 41 | /* 42 | * efun 定义 43 | * 44 | * FluffOS efun 文件中的文档注释是从 FluffOS 源代码中生成的。 45 | * https://github.com/fluffos/fluffos/tree/master/docs 46 | * 47 | * 请参阅 https://github.com/fluffos/fluffos/blob/master/Copyright 48 | * 获取许可证/版权信息。 49 | */ 50 | 51 | 52 | #include "arrays.zh-cn.h" 53 | #include "async.zh-cn.h" 54 | #include "buffers.zh-cn.h" 55 | #include "calls.zh-cn.h" 56 | #include "contrib.zh-cn.h" 57 | #include "db.zh-cn.h" 58 | #include "ed.zh-cn.h" 59 | #include "external.zh-cn.h" 60 | #include "filesystem.zh-cn.h" 61 | #include "floats.zh-cn.h" 62 | #include "functions.zh-cn.h" 63 | #include "general.zh-cn.h" 64 | #include "interactive.zh-cn.h" 65 | #include "internals.zh-cn.h" 66 | #include "mappings.zh-cn.h" 67 | #include "misc.zh-cn.h" 68 | #include "mudlib.zh-cn.h" 69 | #include "numbers.zh-cn.h" 70 | #include "objects.zh-cn.h" 71 | #include "parsing.zh-cn.h" 72 | #include "pcre.zh-cn.h" 73 | #include "sockets.zh-cn.h" 74 | #include "strings.zh-cn.h" 75 | #include "system.zh-cn.h" 76 | 77 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/external.zh-cn.h: -------------------------------------------------------------------------------- 1 | // external.h 2 | 3 | /** 4 | * external_start() - 执行一个外部于驱动的shell命令 5 | * 6 | * 执行一个外部于驱动的shell命令。 7 | * 8 | * 您希望执行的命令必须添加到运行时配置中。 9 | * 这些枚举的命令可以通过它们的编号作为第一个参数 `external_index` 调用 external_start。 10 | * 11 | * 此函数返回您应该记录的套接字号码,以便后续处理外部命令的结果。 12 | * 13 | * `args` - 传递给外部命令的参数数组。 14 | * `read_call_back` - 当数据可用时,此函数将被调用,参数是包含该数据的字符串。 15 | * `write_call_back` - 我不太确定会向外部命令写入什么,但这是一个必需的参数。 16 | * `close_call_back` - 当套接字关闭时,将调用此函数。 17 | * 18 | * 这是一个使用本文件提供的信息的非常基本的示例。 19 | * 20 | */ 21 | int external_start(int external_index, 22 | string *args, 23 | string|function read_call_back, 24 | string|function write_call_back, 25 | string|function close_call_back); 26 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/floats.zh-cn.h: -------------------------------------------------------------------------------- 1 | // floats.h 2 | 3 | /** 4 | * to_int - 将浮点数或缓冲区转换为整数 5 | * 6 | * 如果 'x' 是浮点数,to_int() 调用返回与 'x' 等效的整数类型的数字 7 | * (去掉小数部分,并向下取整)。 8 | * 9 | * 如果 'x' 是缓冲区,调用返回在缓冲区中嵌入的整数(以网络字节顺序)。 10 | * 11 | * 如果 'x' 是字符串,调用将尝试将字符串转换为整数。转换将从第一个字符开始, 12 | * 在最后一个非数字的字符串表示数字之前停止并返回。如果转换不成功, 13 | * 将返回 UNDEFINED。 14 | * 15 | */ 16 | int to_int( float | string | buffer x); 17 | 18 | /** 19 | * tan() - 返回浮点数的正切 20 | * 21 | * 返回其参数 'f' 的正切值,单位为弧度。 22 | * 23 | */ 24 | float tan( float f ); 25 | 26 | /** 27 | * sqrt() - 返回浮点数的平方根 28 | * 29 | * sqrt() 返回其参数 'f' 的非负平方根。'f' 的值不能为负数。 30 | * 31 | */ 32 | float sqrt( float f ); 33 | 34 | /** 35 | * sin() - 返回浮点数的正弦 36 | * 37 | * 返回其参数 'f' 的正弦值,单位为弧度。 38 | * 39 | */ 40 | float sin( float f ); 41 | 42 | /** 43 | * round() - 四舍五入浮点数 44 | * 45 | * 返回 'f' 的四舍五入值,类型为浮点数。 46 | * 47 | */ 48 | float round( float f ); 49 | 50 | /** 51 | * pow() - 计算浮点数的指数 52 | * 53 | * pow() 返回 x 的 y 次方。如果 x 为 0.0,则 y 必须为正数。如果 x 为负数, 54 | * 则 y 必须为整数。 55 | * 56 | */ 57 | float pow( float x, float y ); 58 | 59 | /** 60 | * log() - 返回浮点数的自然对数 61 | * 62 | * 返回其参数 'f' 的自然对数。'f' 必须是正数。 63 | * 64 | */ 65 | float log( float f ); 66 | 67 | /** 68 | * floor() - 将浮点数向下舍入到最接近的整数 69 | * 70 | * 返回(作为浮点数)小于或等于 f 的最接近的整数。 71 | * 72 | */ 73 | float floor( float f ); 74 | 75 | /** 76 | * floatp() - 确定给定变量是否为浮点数 77 | * 78 | * 如果 'arg' 是浮点数,则返回 1,否则返回 0。 79 | * 80 | */ 81 | int floatp( mixed arg ); 82 | 83 | /** 84 | * exp() - 计算 e 的浮点数次方 85 | * 86 | * exp() 返回 e^f。 87 | * 88 | */ 89 | float exp( float f ); 90 | 91 | /** 92 | * cos() - 返回浮点数的余弦 93 | * 94 | * 返回其参数 'f' 的余弦值,单位为弧度。 95 | * 96 | */ 97 | float cos( float f ); 98 | 99 | /** 100 | * ceil() - 将浮点数向上舍入到最接近的整数 101 | * 102 | * 返回(作为浮点数)大于或等于 f 的最接近的整数。 103 | * 104 | */ 105 | float ceil( float f ); 106 | 107 | /** 108 | * atan() - 返回浮点数的反正切 109 | * 110 | * 返回其参数 'f' 的反正切值,单位为弧度。 111 | * 112 | */ 113 | float atan( float f ); 114 | 115 | /** 116 | * asin() - 返回浮点数的反正弦 117 | * 118 | * 返回其参数 'f' 的反正弦值,单位为弧度。 119 | * 120 | */ 121 | float asin( float f ); 122 | 123 | /** 124 | * acos() - 返回浮点数的反余弦 125 | * 126 | * 返回其参数 'f' 的反余弦值,单位为弧度。 127 | * 128 | */ 129 | float acos( float f ); 130 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/functions.zh-cn.h: -------------------------------------------------------------------------------- 1 | // functions.h 2 | 3 | /** 4 | * functionp() - 确定给定变量是否是函数指针,如果是,则返回其类型 5 | * @param arg - 要检查的变量 6 | * @returns {arg is function} 如果 arg 是函数指针,则返回 1,否则返回 0 7 | * 8 | * 如果 'arg' 是一个函数指针,则返回非零值,否则返回零 (0)。 9 | * 函数指针是类型为 'function' 的变量,如文档中所述,例如: 10 | * ```c 11 | * f = (: obj, func :); 12 | * ``` 13 | * 返回值使用在驱动程序包含文件 "include/function.h" 中给出的值来指示函数指针的类型。 14 | * 15 | * 函数指针类型 值 16 | * --------------------- ----- 17 | * call_other FP_CALL_OTHER 18 | * lfun FP_LOCAL 19 | * efun FP_EFUN 20 | * simul_efun FP_SIMUL 21 | * functional FP_FUNCTIONAL 22 | * 23 | * 此外,在某些情况下,将添加以下值: 24 | * FP_HAS_ARGUMENTS 提供了参数 25 | * FP_OWNER_DESTED 创建者已被销毁 26 | * FP_NOT_BINDABLE 不可重新绑定 27 | * 28 | * 最后一组值是位值,可以使用位运算进行测试。 值 FP_MASK 用于忽略位值并测试函数指针的基本类型。 29 | * 30 | * 示例: 31 | * 32 | * 检查一个函数变量是否是 efun 指针: 33 | * ```c 34 | * if ((functionp(f) & FP_MASK) == FP_EFUN) ... 35 | * ``` 36 | * 检查它是否有参数: 37 | * ```c 38 | * if (functionp(f) & FP_HAS_ARGUMENTS) ... 39 | * ``` 40 | */ 41 | int functionp( mixed arg ); 42 | 43 | /** 44 | * evaluate() - 评估一个函数指针 45 | * 46 | * 如果 f 是一个函数,则使用其余参数调用 f。否则,返回 f。 evaluate(f, ...) 等同于 (*f)(...)。 47 | * 48 | */ 49 | mixed evaluate(mixed f... ); 50 | 51 | /** 52 | * defer() - 在当前函数结束后执行函数 53 | * 54 | * 在当前函数结束时调用函数指针 *f(即使是由于运行时错误导致的)。 55 | * 56 | * 例如: 57 | * 58 | * void create() 59 | * { 60 | * ::create(); 61 | * 62 | * defer( (: enable_commands :) ); 63 | * } 64 | * 65 | * defer() 函数的效果是它会导致 enable_commands() efun 在 create() 函数执行结束后被调用。传递给 defer() 的参数可以是任何函数类型。 66 | * 67 | */ 68 | void defer(function f); 69 | 70 | /** 71 | * bind() - 更改函数指针的所有者 72 | * 73 | * 返回一个与 f 完全相同的函数指针,但属于对象 'ob',而不是创建 f 的对象。 如果 'f' 的创建者已经被销毁,或者 f 是一个 efun 指针指向一个对 'this_object' 做某事的 efun,则很有用。 74 | * 75 | * 例如: 76 | * 77 | * void make_living(object ob) { 78 | * function f; 79 | * 80 | * f = bind( (: enable_commands :), ob ); 81 | * 82 | * evaluate(f); } 83 | * 84 | * 上述效果与 'ob' 自身评估 enable_commands() efun 的效果相同。 请注意,这涉及到安全风险,因为 bind() 允许您强制另一个对象运行一段代码。 为了防止这种情况,必须有一个有效的 valid_bind() 主应用程序返回 1,否则调用 bind() 将失败。 85 | * 86 | */ 87 | function bind(function f, object ob); 88 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/misc.zh-cn.h: -------------------------------------------------------------------------------- 1 | // test_bit.md.h 2 | 3 | /** 4 | * test_bit 5 | * set_bit() - 在比特字符串中设置一个比特 6 | * 7 | * 如果比特 'n' 在字符串 'str' 中被设置,返回 0 或 1。 8 | * 9 | */ 10 | int test_bit( string str, int n ); 11 | 12 | // test_load.md.h 13 | 14 | /** 15 | * test_load 16 | * test_load - 测试文件是否可加载 17 | * 18 | * 测试一个文件是否可加载。如果文件可加载,将返回 1, 19 | 否则返回 0。如果尝试加载的文件包含错误, 20 | 将会报告这些错误,在这种情况下,你可能需要将 21 | 函数调用包装在 catch 语句中以获取 0 的结果。 22 | * 23 | */ 24 | int test_load( string filename ); 25 | 26 | 27 | /** 28 | * set_notify_destruct() - 设置对象在被销毁时通知 29 | * @param flag 如果 flag 设置为 1,则对象将在被销毁时 30 | * 接收对函数 on_destruct() 的调用。如果 flag 设置为 0, 31 | * 对象将不会收到此通知。 32 | * @details 33 | * 切换对象中的一个标志,以决定它是否会在被销毁时 34 | * 接到通知。如果 flag 设置为 1,对象将在被销毁时 35 | * 接收对函数 on_destruct() 的调用。如果 flag 设置为 0, 36 | * 对象将不会收到此通知。 37 | * 默认情况下,对象不会收到此通知。要接收对 38 | * on_destruct() 的调用,对象必须在其生命周期内 39 | * 的某个时刻调用 set_notify_destruct(1)。 40 | * set_notify_destruct() efun 只能从希望接收 41 | * 通知的对象内部调用。 42 | */ 43 | void set_notify_destruct(int flag); 44 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/numbers.zh-cn.h: -------------------------------------------------------------------------------- 1 | // numbers.h 2 | 3 | /** 4 | * to_float - 将一个整数转换为浮点数 5 | * 6 | * to_float() 调用返回与整数 'i' 等值的 'float' 类型的数字。 7 | * 8 | */ 9 | float to_float(int i); 10 | float to_float(string i); 11 | 12 | /** 13 | * secure_random() - 返回一个伪随机数,这个数应该是不可预测的,但可能略慢。 14 | * 15 | * 返回一个从范围 [0 .. (n -1)](包括)内的密码学安全随机数。 16 | * 17 | * 在 Linux 和 OSX 上,该函数显式使用来自 /dev/urandom 的随机性,在 Windows 上则是实现定义。 18 | * 19 | */ 20 | int secure_random( int n ); 21 | 22 | /** 23 | * random() - 返回一个伪随机数,这个数适合一般模拟,但是可能是可预测的。 24 | * 25 | * 返回一个从范围 [0 .. (n -1)](包括)内的伪随机数。 26 | * 27 | */ 28 | int random( int n ); 29 | 30 | /** 31 | * intp() - 确定给定变量是否是整数 32 | * 33 | * 如果 'arg' 是一个整数,则返回 1,否则返回零(0)。 34 | * 35 | */ 36 | int intp( mixed arg ); 37 | -------------------------------------------------------------------------------- /efuns/fluffos/zh-cn/pcre.zh-cn.h: -------------------------------------------------------------------------------- 1 | // pcre.h 2 | 3 | /** 4 | * pcre_version() - 返回使用的已编译PCRE库的版本 5 | * 6 | * 返回使用的已编译PCRE库的版本 7 | * 8 | */ 9 | string pcre_version(void); 10 | 11 | /** 12 | * pcre_replace_callback() - 字符串替换使用回调函数获取替换字符串 13 | * 14 | * 返回一个字符串,其中所有捕获的组已被函数指针fun或对象ob中的函数fun的返回值替换。(使用匹配字符串和匹配编号调用,编号从0开始) 15 | * 16 | */ 17 | string pcre_replace_callback(string input, string pattern, string|function, mixed *args...); 18 | 19 | /** 20 | * pcre_replace() 21 | * 22 | * 返回一个字符串,其中所有捕获的组已被替换数组的元素替换。子组数量和替换数组的大小必须匹配。 23 | * 24 | */ 25 | string pcre_replace(string input, string pattern, string *replacments); 26 | 27 | /** 28 | * pcre_match_all() - 查找所有匹配项 29 | * 30 | * 类似于php的preg_match_all,这个EFUN返回一个字符串数组的数组,包含所有匹配项和捕获的组。 31 | * 32 | */ 33 | mixed pcre_match_all(string input, string pattern); 34 | 35 | /** 36 | * pcre_match() - 正则表达式处理器 37 | * 38 | * 由于向后兼容的原因与正则表达式efun类似,但利用了PCRE库。 39 | * 40 | */ 41 | mixed pcre_match(string|string *lines, string pattern, void|int flag); 42 | 43 | /** 44 | * pcre_extract() - 提取匹配部分 45 | * 46 | * 返回模式中指定的捕获组的数组。 47 | * 48 | */ 49 | string *pcre_extract(string input, string pattern); 50 | 51 | /** 52 | * pcre_cache() - 返回pcre缓存的内容 53 | * 54 | * 返回pcre缓存的内容(不是很有用)。 55 | * 56 | */ 57 | mapping pcre_cache(void); 58 | 59 | /** 60 | * pcre_assoc() - 正则模式子字符串提取器 61 | * 62 | * 由于向后兼容的原因与reg_assoc efun类似,但利用了PCRE库。 63 | * 64 | */ 65 | varargs mixed *pcre_assoc(string input, string *patterns, 66 | mixed *token_aray, 67 | mixed default_value); 68 | -------------------------------------------------------------------------------- /efuns/ldmud/lpc-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "driver": { 3 | "type": "ldmud" 4 | }, 5 | "include": ["./"], 6 | "compilerOptions": { 7 | "noLib": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "jest"; 2 | 3 | const config: Config = { 4 | collectCoverage: true, 5 | collectCoverageFrom: [ 6 | "server/src/**/*.ts", 7 | "!server/src/tests/**", 8 | "!**/node_modules/**", 9 | ], 10 | coverageDirectory: "coverage", 11 | coverageProvider: "v8", 12 | coverageReporters: ["json", "text", "html"], 13 | coverageThreshold: { 14 | global: { 15 | statements: 54, 16 | branches: 49, 17 | functions: 43, 18 | lines: 54, 19 | }, 20 | }, 21 | moduleDirectories: ["node_modules"], 22 | workerIdleMemoryLimit: "500MB", 23 | moduleFileExtensions: ["ts", "js", "mjs", "cjs", "json"], 24 | extensionsToTreatAsEsm: [".ts"], 25 | moduleNameMapper: { 26 | "(.+)\\.js": "$1", 27 | }, 28 | preset: "ts-jest/presets/js-with-ts-esm", 29 | 30 | resetMocks: false, 31 | 32 | // A list of paths to directories that Jest should use to search for files in 33 | roots: ["server/src/tests"], 34 | 35 | setupFilesAfterEnv: [], 36 | testEnvironment: "node", 37 | 38 | testEnvironmentOptions: {}, 39 | 40 | testMatch: ["**/tests/**/*.spec.ts"], 41 | 42 | testPathIgnorePatterns: [], 43 | 44 | testTimeout: 30000, 45 | 46 | transform: { 47 | "\\.ts?$": ["ts-jest", { useESM: true }], 48 | }, 49 | 50 | transformIgnorePatterns: ["node_modules/"], 51 | }; 52 | 53 | export default config; 54 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@lpc-lang/core", 3 | "displayName": "LPC", 4 | "description": "LPC Language Compiler Library", 5 | "version": "1.1.39", 6 | "scripts": { 7 | }, 8 | "author": "jlchmura", 9 | "publisher": "jlchmura", 10 | "license": "MIT", 11 | "typings": "./lpc/lpc.d.ts", 12 | "main": "./src/lpc.js", 13 | "bin": { 14 | "lpc": "./bin/lpc", 15 | "lpcserver": "./bin/lpcserver" 16 | }, 17 | "categories": [ 18 | "Programming Languages" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/jlchmura/lpc-language-server" 23 | }, 24 | "keywords": [ 25 | "LPC", 26 | "language", 27 | "server", 28 | "Lars Pensjö", 29 | "C", 30 | "MUD", 31 | "LPMUD", 32 | "LDMUD", 33 | "FluffOS", 34 | "MudOS", 35 | "VSCode" 36 | ], 37 | "bugs": { 38 | "url": "https://github.com/jlchmura/lpc-language-server/issues" 39 | }, 40 | "homepage": "https://github.com/jlchmura/lpc-language-server#readme", 41 | "dependencies": { 42 | "glob": "^10.3.15", 43 | "jsonc-parser": "^3.3.1", 44 | "setimmediate": "^1.0.5", 45 | "vscode-uri": "^3.0.8" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lpc-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlchmura/lpc-language-server/040d1d1edc7bc5a29988f63fc314cf66dff3a839/lpc-icon.png -------------------------------------------------------------------------------- /schemas/lpc-config.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowTrailingCommas": true, 3 | "title": "JSON schema for the LPC parser's configuration file", 4 | "type": "object", 5 | "default": { 6 | "defines": [ 7 | { 8 | "__VERSION__": "1.0" 9 | } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lpc-server", 3 | "description": "LPC Language Server", 4 | "version": "0.0.1", 5 | "author": "jlchmura", 6 | "license": "MIT", 7 | "engines": { 8 | "node": "*" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/jlchmura/lpc-language-server" 13 | }, 14 | "dependencies": { 15 | "vscode-languageserver": "^9.0.1", 16 | "vscode-languageserver-textdocument": "^1.0.8" 17 | }, 18 | "scripts": {} 19 | } 20 | -------------------------------------------------------------------------------- /server/src/cancellationToken/serverCancellationToken.ts: -------------------------------------------------------------------------------- 1 | import * as lpc from "../lpc/lpc.js"; 2 | 3 | /** 4 | * Test server cancellation token used to mock host token cancellation requests. 5 | * The cancelAfterRequest constructor param specifies how many isCancellationRequested() calls 6 | * should be made before canceling the token. The id of the request to cancel should be set with 7 | * setRequestToCancel(); 8 | */ 9 | export class ServerCancellationToken implements lpc.server.ServerCancellationToken { 10 | private currentId: number | undefined = -1; 11 | private requestToCancel = -1; 12 | private isCancellationRequestedCount = 0; 13 | 14 | constructor(private logger: lpc.server.Logger, private cancelAfterRequest = 0) { 15 | } 16 | 17 | setRequest(requestId: number) { 18 | this.currentId = requestId; 19 | 20 | this.logger.msg(`TestServerCancellationToken:: Cancellation Request id:: ${requestId}`); 21 | } 22 | 23 | setRequestToCancel(requestId: number) { 24 | this.logger.msg(`TestServerCancellationToken:: Setting request to cancel:: ${requestId}`); 25 | this.resetToken(); 26 | this.requestToCancel = requestId; 27 | } 28 | 29 | resetRequest(requestId: number) { 30 | this.logger.msg(`TestServerCancellationToken:: resetRequest:: ${requestId} is ${requestId === this.currentId ? "as expected" : `expected to be ${this.currentId}`}`); 31 | lpc.Debug.assertEqual(requestId, this.currentId, "unexpected request id in cancellation"); 32 | this.currentId = undefined; 33 | } 34 | 35 | isCancellationRequested() { 36 | this.isCancellationRequestedCount++; 37 | // If the request id is the request to cancel and isCancellationRequestedCount 38 | // has been met then cancel the request. Ex: cancel the request if it is a 39 | // nav bar request & isCancellationRequested() has already been called three times. 40 | const result = this.requestToCancel === this.currentId && this.isCancellationRequestedCount >= this.cancelAfterRequest; 41 | if (result) this.logger.msg(`TestServerCancellationToken:: Cancellation is requested`); 42 | return result; 43 | } 44 | 45 | resetToken() { 46 | this.currentId = -1; 47 | this.isCancellationRequestedCount = 0; 48 | this.requestToCancel = -1; 49 | } 50 | } -------------------------------------------------------------------------------- /server/src/cancellationToken/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": [ 4 | "node" 5 | ] 6 | }, 7 | "include": ["**/*"] 8 | } 9 | -------------------------------------------------------------------------------- /server/src/cli/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | export * from "../../compiler/_namespaces/lpc.js"; -------------------------------------------------------------------------------- /server/src/cli/lpc.ts: -------------------------------------------------------------------------------- 1 | import * as lpc from "../lpc/lpc.js"; 2 | 3 | // This file actually uses arguments passed on commandline and executes it 4 | 5 | // enable deprecation logging 6 | lpc.Debug.loggingHost = { 7 | log(_level, s) { 8 | lpc.sys.write(`${s || ""}${lpc.sys.newLine}`); 9 | }, 10 | }; 11 | 12 | if (lpc.Debug.isDebugging) { 13 | lpc.Debug.enableDebugInfo(); 14 | } 15 | 16 | if (lpc.sys.tryEnableSourceMapsForHost && /^development$/i.test(lpc.sys.getEnvironmentVariable("NODE_ENV"))) { 17 | lpc.sys.tryEnableSourceMapsForHost(); 18 | } 19 | 20 | if (lpc.sys.setBlocking) { 21 | lpc.sys.setBlocking(); 22 | } 23 | 24 | // our console output is still verbose, so mask console output 25 | console.log = lpc.noop; 26 | console.debug = lpc.noop; 27 | console.info = lpc.noop; 28 | console.warn = lpc.noop; 29 | 30 | lpc.executeCommandLine(lpc.sys, lpc.sys.args, onMessage); 31 | 32 | function onMessage(msg: string, msgType?: lpc.ExecuteCommandMsgType) { 33 | lpc.sys.write(msg); 34 | } -------------------------------------------------------------------------------- /server/src/compiler/_namespaces/lpc.moduleSpecifiers.ts: -------------------------------------------------------------------------------- 1 | /* Generated file to emulate the ts.moduleSpecifiers namespace. */ 2 | 3 | export * from "../moduleSpecifiers.js"; 4 | -------------------------------------------------------------------------------- /server/src/compiler/_namespaces/lpc.performance.ts: -------------------------------------------------------------------------------- 1 | 2 | export * from "../performance.js"; 3 | -------------------------------------------------------------------------------- /server/src/compiler/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | export * from "../corePublic.js"; 2 | export * from "../core.js"; 3 | export * from "../performanceCore.js"; 4 | export * from "../perfLoger.js"; 5 | export * from "../debug.js"; 6 | export * from "../tracing.js"; 7 | export * from "../types.js"; 8 | export * from "../diagnosticInformation.js"; 9 | export * from "../scanner.js"; 10 | export * from "../lpcJsHelpers.js"; 11 | export * from "../utilitiesPublic.js"; 12 | export * from "../utilities.js"; 13 | export * from "../factory/baseNodeFactory.js"; 14 | export * from "../factory/parenthesizerRules.js"; 15 | export * from "../factory/nodeFactory.js"; 16 | export * from "../factory/nodeChildren.js"; 17 | export * from "../factory/emitHelper.js"; 18 | export * from "../factory/emitNode.js"; 19 | export * from "../factory/utilitiesPublic.js"; 20 | export * from "../factory/utilities.js"; 21 | export * from "../lpcFileHandler.js"; 22 | export * from "../parser.js"; 23 | export * from "../commandLineParser.js"; 24 | export * from "../moduleNameResolver.js"; 25 | export * from "../nodeTests.js"; 26 | export * from "../binder.js"; 27 | export * from "../checker.js"; 28 | export * from "../path.js"; 29 | export * from "../builderPublic.js"; 30 | export * from "../visitorPublic.js"; 31 | export * from "../sourcemap.js"; 32 | export * from "../watchPublic.js"; 33 | export * from "../watch.js"; 34 | export * from "../watchUtilities.js"; 35 | export * from "../sys.js"; 36 | export * from "../program.js"; 37 | export * from "../transformers.js"; 38 | export * from "../transformers/declarations.js"; 39 | export * from "../emitter.js"; 40 | export * from "../resolutionCache.js"; 41 | export * from "../lpcbuild.js"; 42 | export * from "../lpcbuildPublic.js"; 43 | export * from "../executeCommandLine.js"; 44 | export * from "../expressionToTypeNode.js"; 45 | import * as moduleSpecifiers from "./lpc.moduleSpecifiers.js"; 46 | export { moduleSpecifiers }; 47 | import * as performance from "./lpc.performance.js"; 48 | export { performance }; 49 | -------------------------------------------------------------------------------- /server/src/compiler/corePublic.ts: -------------------------------------------------------------------------------- 1 | // WARNING: The script `configurePrerelease.ts` uses a regexp to parse out these values. 2 | // If changing the text in this section, be sure to test `configurePrerelease` too. 3 | export const versionMajorMinor = "1.1"; 4 | // The following is baselined as a literal template type without intervention 5 | /** The version of the TypeScript compiler release */ 6 | export const version = "1.1.18" as string; 7 | 8 | export const diagnosticPrefix = "LPC" as string; 9 | 10 | /** 11 | * Type of objects whose values are all of the same type. 12 | * The `in` and `for-in` operators can *not* be safely used, 13 | * since `Object.prototype` may be modified by outside code. 14 | */ 15 | export interface MapLike { 16 | [index: string]: T; 17 | } 18 | 19 | export interface SortedReadonlyArray extends ReadonlyArray { 20 | " __sortedArrayBrand": any; 21 | } 22 | 23 | export interface SortedArray extends Array { 24 | " __sortedArrayBrand": any; 25 | } 26 | 27 | /** @internal */ 28 | export type EqualityComparer = (a: T, b: T) => boolean; 29 | 30 | /** @internal */ 31 | export type Comparer = (a: T, b: T) => Comparison; 32 | 33 | /** @internal */ 34 | export const enum Comparison { 35 | LessThan = -1, 36 | EqualTo = 0, 37 | GreaterThan = 1, 38 | } 39 | 40 | 41 | 42 | /** 43 | * Common read methods for ES6 Map/Set. 44 | * 45 | * @internal 46 | */ 47 | export interface ReadonlyCollection { 48 | readonly size: number; 49 | has(key: K): boolean; 50 | keys(): IterableIterator; 51 | } -------------------------------------------------------------------------------- /server/src/compiler/factory/baseNodeFactory.ts: -------------------------------------------------------------------------------- 1 | import { Node, objectAllocator, SyntaxKind } from "../_namespaces/lpc.js"; 2 | 3 | /** 4 | * A `BaseNodeFactory` is an abstraction over an `ObjectAllocator` that handles caching `Node` constructors 5 | * and allocating `Node` instances based on a set of predefined types. 6 | * 7 | * @internal 8 | */ 9 | export interface BaseNodeFactory { 10 | createBaseSourceFileNode(kind: SyntaxKind.SourceFile): Node; 11 | createBaseIdentifierNode(kind: SyntaxKind.Identifier): Node; 12 | createBaseTokenNode(kind: SyntaxKind): Node; 13 | createBaseNode(kind: SyntaxKind): Node; 14 | } 15 | 16 | /** 17 | * Creates a `BaseNodeFactory` which can be used to create `Node` instances from the constructors provided by the object allocator. 18 | * 19 | * @internal 20 | */ 21 | export function createBaseNodeFactory(): BaseNodeFactory { 22 | let NodeConstructor: new ( 23 | kind: SyntaxKind, 24 | pos: number, 25 | end: number 26 | ) => Node; 27 | let TokenConstructor: new ( 28 | kind: SyntaxKind, 29 | pos: number, 30 | end: number 31 | ) => Node; 32 | let IdentifierConstructor: new ( 33 | kind: SyntaxKind.Identifier, 34 | pos: number, 35 | end: number 36 | ) => Node; 37 | let SourceFileConstructor: new ( 38 | kind: SyntaxKind.SourceFile, 39 | pos: number, 40 | end: number 41 | ) => Node; 42 | 43 | return { 44 | createBaseSourceFileNode, 45 | createBaseIdentifierNode, 46 | createBaseTokenNode, 47 | createBaseNode, 48 | }; 49 | 50 | function createBaseSourceFileNode(kind: SyntaxKind.SourceFile): Node { 51 | return new (SourceFileConstructor || 52 | (SourceFileConstructor = 53 | objectAllocator.getSourceFileConstructor()))( 54 | kind, 55 | /*pos*/ -1, 56 | /*end*/ -1 57 | ); 58 | } 59 | 60 | function createBaseIdentifierNode(kind: SyntaxKind.Identifier): Node { 61 | return new (IdentifierConstructor || 62 | (IdentifierConstructor = 63 | objectAllocator.getIdentifierConstructor()))( 64 | kind, 65 | /*pos*/ -1, 66 | /*end*/ -1 67 | ); 68 | } 69 | 70 | function createBaseTokenNode(kind: SyntaxKind): Node { 71 | return new (TokenConstructor || 72 | (TokenConstructor = objectAllocator.getTokenConstructor()))( 73 | kind, 74 | /*pos*/ -1, 75 | /*end*/ -1 76 | ); 77 | } 78 | 79 | function createBaseNode(kind: SyntaxKind): Node { 80 | return new (NodeConstructor || 81 | (NodeConstructor = objectAllocator.getNodeConstructor()))( 82 | kind, 83 | /*pos*/ -1, 84 | /*end*/ -1 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /server/src/compiler/factory/nodeChildren.ts: -------------------------------------------------------------------------------- 1 | import { Debug, emptyArray, firstOrUndefined, isNodeKind, Node, SourceFileLike, SyntaxKind, SyntaxList } from "../_namespaces/lpc.js"; 2 | 3 | const sourceFileToNodeChildren = new WeakMap>(); 4 | 5 | /** @internal */ 6 | export function getNodeChildren(node: Node, sourceFile: SourceFileLike): readonly Node[] | undefined { 7 | const kind = node.kind; 8 | if (!isNodeKind(kind)) { 9 | return emptyArray; 10 | } 11 | if (kind === SyntaxKind.SyntaxList) { 12 | return (node as SyntaxList)._children; 13 | } 14 | 15 | return sourceFileToNodeChildren.get(sourceFile)?.get(node); 16 | } 17 | 18 | /** @internal */ 19 | export function setNodeChildren(node: Node, sourceFile: SourceFileLike, children: readonly Node[]): readonly Node[] { 20 | if (node.kind === SyntaxKind.SyntaxList) { 21 | // SyntaxList children are always eagerly created in the process of 22 | // creating their parent's `children` list. We shouldn't need to set them here. 23 | Debug.fail("Should not need to re-set the children of a SyntaxList."); 24 | // JC: this can happen because of the change I made to empty syntax list creation. 25 | // return empty array; 26 | return []; 27 | } 28 | 29 | let map = sourceFileToNodeChildren.get(sourceFile); 30 | if (map === undefined) { 31 | map = new WeakMap(); 32 | sourceFileToNodeChildren.set(sourceFile, map); 33 | } 34 | map.set(node, children); 35 | return children; 36 | } -------------------------------------------------------------------------------- /server/src/compiler/factory/nodeConverters.ts: -------------------------------------------------------------------------------- 1 | import { NodeConverters, notImplemented } from "../_namespaces/lpc"; 2 | 3 | /** @internal */ 4 | export const nullNodeConverters: NodeConverters = { 5 | convertToFunctionBlock: notImplemented, 6 | convertToFunctionExpression: notImplemented, 7 | //convertToClassExpression: notImplemented, 8 | // convertToArrayAssignmentElement: notImplemented, 9 | // convertToObjectAssignmentElement: notImplemented, 10 | // convertToAssignmentPattern: notImplemented, 11 | // convertToObjectAssignmentPattern: notImplemented, 12 | // convertToArrayAssignmentPattern: notImplemented, 13 | // convertToAssignmentElementTarget: notImplemented, 14 | }; 15 | -------------------------------------------------------------------------------- /server/src/compiler/factory/utilitiesPublic.ts: -------------------------------------------------------------------------------- 1 | import { HasModifiers, Node, setTextRangePosEnd, SyntaxKind, TextRange } from "../_namespaces/lpc"; 2 | 3 | export function setTextRange(range: T, location: TextRange | undefined): T { 4 | return location ? setTextRangePosEnd(range, location.pos, location.end) : range; 5 | } 6 | 7 | export function canHaveModifiers(node: Node): node is HasModifiers { 8 | const kind = node.kind; 9 | return kind === SyntaxKind.TypeParameter 10 | || kind === SyntaxKind.Parameter 11 | || kind === SyntaxKind.PropertySignature 12 | || kind === SyntaxKind.PropertyDeclaration 13 | || kind === SyntaxKind.MethodSignature 14 | || kind === SyntaxKind.MethodDeclaration 15 | || kind === SyntaxKind.IndexSignature 16 | || kind === SyntaxKind.FunctionExpression 17 | || kind === SyntaxKind.VariableStatement 18 | || kind === SyntaxKind.FunctionDeclaration 19 | || kind === SyntaxKind.ArrowFunction 20 | || kind === SyntaxKind.ClassExpression 21 | || kind === SyntaxKind.ClassDeclaration 22 | || kind === SyntaxKind.TypeAliasDeclaration 23 | ; 24 | } -------------------------------------------------------------------------------- /server/src/compiler/lpcbuild.ts: -------------------------------------------------------------------------------- 1 | import { Extension, ResolvedConfigFileName, combinePaths, fileExtensionIs } from "./_namespaces/lpc.js"; 2 | 3 | /** @internal */ 4 | export function resolveConfigFileProjectName(project: string): ResolvedConfigFileName { 5 | if (fileExtensionIs(project, Extension.Json)) { 6 | return project as ResolvedConfigFileName; 7 | } 8 | 9 | return combinePaths(project, "lpc-config.json") as ResolvedConfigFileName; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /server/src/compiler/moduleSpecifiers.ts: -------------------------------------------------------------------------------- 1 | import { CharacterCodes, startsWith } from "./_namespaces/lpc"; 2 | 3 | /** @internal */ 4 | export function countPathComponents(path: string): number { 5 | let count = 0; 6 | for (let i = startsWith(path, "./") ? 2 : 0; i < path.length; i++) { 7 | if (path.charCodeAt(i) === CharacterCodes.slash) count++; 8 | } 9 | return count; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/compiler/perfLoger.ts: -------------------------------------------------------------------------------- 1 | /** @internal */ 2 | export interface PerfLogger { 3 | logEvent(msg: string): void; 4 | logErrEvent(msg: string): void; 5 | logPerfEvent(msg: string): void; 6 | logInfoEvent(msg: string): void; 7 | logStartCommand(command: string, msg: string): void; 8 | logStopCommand(command: string, msg: string): void; 9 | logStartUpdateProgram(msg: string): void; 10 | logStopUpdateProgram(msg: string): void; 11 | logStartUpdateGraph(): void; 12 | logStopUpdateGraph(): void; 13 | logStartResolveModule(name: string): void; 14 | logStopResolveModule(success: string): void; 15 | logStartParseSourceFile(filename: string): void; 16 | logStopParseSourceFile(): void; 17 | logStartReadFile(filename: string): void; 18 | logStopReadFile(): void; 19 | logStartBindFile(filename: string): void; 20 | logStopBindFile(): void; 21 | logStartScheduledOperation(operationId: string): void; 22 | logStopScheduledOperation(): void; 23 | } 24 | 25 | // Load optional module to enable Event Tracing for Windows 26 | // See https://github.com/microsoft/typescript-etw for more information 27 | let etwModule: typeof import("@microsoft/typescript-etw") | undefined; 28 | try { 29 | const etwModulePath = process.env.TS_ETW_MODULE_PATH ?? "./node_modules/@microsoft/typescript-etw"; 30 | 31 | // require() will throw an exception if the module is not found 32 | // It may also return undefined if not installed properly 33 | etwModule = require(etwModulePath); 34 | } 35 | catch (e) { 36 | etwModule = undefined; 37 | } 38 | 39 | /** 40 | * Performance logger that will generate ETW events if possible - check for `logEvent` member, as `etwModule` will be `{}` when browserified 41 | * 42 | * @internal 43 | */ 44 | export const perfLogger: PerfLogger | undefined = etwModule?.logEvent ? etwModule : undefined; 45 | -------------------------------------------------------------------------------- /server/src/compiler/performanceCore.ts: -------------------------------------------------------------------------------- 1 | // The following definitions provide the minimum compatible support for the Web Performance User Timings API 2 | // between browsers and NodeJS: 3 | 4 | import { isNodeLikeSystem } from "./_namespaces/lpc"; 5 | 6 | /** @internal */ 7 | export interface PerformanceHooks { 8 | shouldWriteNativeEvents: boolean; 9 | performance?: Performance; 10 | performanceTime?: PerformanceTime; 11 | } 12 | 13 | /** @internal */ 14 | export interface PerformanceTime { 15 | now(): number; 16 | timeOrigin: number; 17 | } 18 | 19 | /** @internal */ 20 | export interface Performance extends PerformanceTime { 21 | mark(name: string): void; 22 | measure(name: string, startMark?: string, endMark?: string): void; 23 | clearMeasures(name?: string): void; 24 | clearMarks(name?: string): void; 25 | } 26 | 27 | // Browser globals for the Web Performance User Timings API 28 | declare const performance: Performance | undefined; 29 | 30 | 31 | function tryGetPerformance() { 32 | if (isNodeLikeSystem()) { 33 | try { 34 | // By default, only write native events when generating a cpu profile or using the v8 profiler. 35 | const { performance } = require("perf_hooks") as typeof import("perf_hooks"); 36 | return { 37 | shouldWriteNativeEvents: false, 38 | performance, 39 | }; 40 | } 41 | catch { 42 | // ignore errors 43 | } 44 | } 45 | 46 | if (typeof performance === "object") { 47 | // For now we always write native performance events when running in the browser. We may 48 | // make this conditional in the future if we find that native web performance hooks 49 | // in the browser also slow down compilation. 50 | return { 51 | shouldWriteNativeEvents: true, 52 | performance, 53 | }; 54 | } 55 | 56 | return undefined; 57 | } 58 | 59 | function tryGetPerformanceHooks(): PerformanceHooks | undefined { 60 | const p = tryGetPerformance(); 61 | if (!p) return undefined; 62 | const { shouldWriteNativeEvents, performance } = p; 63 | 64 | const hooks: PerformanceHooks = { 65 | shouldWriteNativeEvents, 66 | performance: undefined, 67 | performanceTime: undefined, 68 | }; 69 | 70 | if (typeof performance.timeOrigin === "number" && typeof performance.now === "function") { 71 | hooks.performanceTime = performance; 72 | } 73 | 74 | if ( 75 | hooks.performanceTime && 76 | typeof performance.mark === "function" && 77 | typeof performance.measure === "function" && 78 | typeof performance.clearMarks === "function" && 79 | typeof performance.clearMeasures === "function" 80 | ) { 81 | hooks.performance = performance; 82 | } 83 | 84 | return hooks; 85 | } 86 | 87 | const nativePerformanceHooks = tryGetPerformanceHooks(); 88 | const nativePerformanceTime = nativePerformanceHooks?.performanceTime; 89 | 90 | /** @internal */ 91 | export function tryGetNativePerformanceHooks() { 92 | return nativePerformanceHooks; 93 | } 94 | 95 | /** 96 | * Gets a timestamp with (at least) ms resolution 97 | * 98 | * @internal 99 | */ 100 | export const timestamp = !!nativePerformanceTime ? () => nativePerformanceTime.now() ?? Date.now() : Date.now; 101 | 102 | 103 | -------------------------------------------------------------------------------- /server/src/compiler/resolver.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlchmura/lpc-language-server/040d1d1edc7bc5a29988f63fc314cf66dff3a839/server/src/compiler/resolver.ts -------------------------------------------------------------------------------- /server/src/compiler/transformers/declarations.ts: -------------------------------------------------------------------------------- 1 | import { contains, DiagnosticWithLocation, EmitHost, EmitResolver, emptyArray, factory, filter, getSourceFilesToEmit, isSourceFileNotJson, SourceFile, transformNodes } from "../_namespaces/lpc.js"; 2 | 3 | /** @internal */ 4 | export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined { 5 | const compilerOptions = host.getCompilerOptions(); 6 | const files = filter(getSourceFilesToEmit(host, file), isSourceFileNotJson); 7 | const result = transformNodes( 8 | resolver, 9 | host, 10 | factory, 11 | compilerOptions, 12 | file ? contains(files, file) ? [file] : emptyArray : files, 13 | [], //TODO [transformDeclarations], 14 | /*allowDtsFiles*/ false, 15 | ); 16 | return result.diagnostics; 17 | } -------------------------------------------------------------------------------- /server/src/config-types.ts: -------------------------------------------------------------------------------- 1 | export enum DiagnosticLevel { 2 | Error = "error", 3 | Warning = "warning", 4 | Info = "info", 5 | Hint = "hint", 6 | None = "none", 7 | } 8 | 9 | export type DiagnosticsInfo = Record; 10 | 11 | export type FilesInfo = { 12 | simul_efun: string; 13 | init_files: string[]; 14 | master: string; 15 | global_include: string; 16 | player: string; 17 | }; 18 | 19 | export enum DriverType { 20 | LDMud = "ldmud", 21 | FluffOS = "fluffos", 22 | } 23 | 24 | export type DriverInfo = { 25 | type: DriverType; 26 | version: string; 27 | }; 28 | 29 | export interface ILpcConfig { 30 | defines: Map; 31 | include: string[]; 32 | exclude: string[]; 33 | driver: DriverInfo; 34 | diagnostics: DiagnosticsInfo; 35 | files: FilesInfo; 36 | allDiagnosticsOff: boolean; 37 | } 38 | -------------------------------------------------------------------------------- /server/src/harness/harnessIO.ts: -------------------------------------------------------------------------------- 1 | import * as lpc from "../lpc/_namespaces/lpc.js"; 2 | import * as fs from "fs"; 3 | import * as pathModule from "path"; 4 | 5 | export function listFiles(path: string, spec: RegExp | undefined, options: { recursive?: boolean; } = {}) { 6 | function filesInFolder(folder: string): string[] { 7 | const { files, directories } = lpc.sys.getAccessibleFileSystemEntries!(folder); 8 | let paths: string[] = []; 9 | for (const file of files) { 10 | const pathToFile = pathModule.join(folder, file); 11 | if (!spec || file.match(spec)) { 12 | paths.push(pathToFile); 13 | } 14 | } 15 | if (options.recursive) { 16 | for (const dir of directories) { 17 | const pathToDir = pathModule.join(folder, dir); 18 | paths = paths.concat(filesInFolder(pathToDir)); 19 | } 20 | } 21 | return paths; 22 | } 23 | 24 | return filesInFolder(path); 25 | } -------------------------------------------------------------------------------- /server/src/lpc/_namespaces/lpc.server.ts: -------------------------------------------------------------------------------- 1 | /* Generated file to emulate the ts.server namespace. */ 2 | 3 | export * from "../../server/_namespaces/lpc.server.js"; 4 | -------------------------------------------------------------------------------- /server/src/lpc/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | /* Generated file to emulate the ts namespace. */ 2 | 3 | export * from "../../compiler/_namespaces/lpc.js"; 4 | export * from "../../services/_namespaces/lpc.js"; 5 | export * from "../../server/_namespaces/lpc.js"; 6 | import * as server from "./lpc.server.js"; 7 | export { server }; 8 | -------------------------------------------------------------------------------- /server/src/lpc/lpc.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Debug, 3 | LogLevel, 4 | } from "./_namespaces/lpc.js"; 5 | 6 | // enable deprecation logging 7 | declare const console: any; 8 | if (typeof console !== "undefined") { 9 | Debug.loggingHost = { 10 | log(level, s) { 11 | switch (level) { 12 | case LogLevel.Error: 13 | return console.error(s); 14 | case LogLevel.Warning: 15 | return console.warn(s); 16 | case LogLevel.Info: 17 | return console.log(s); 18 | case LogLevel.Verbose: 19 | return console.log(s); 20 | } 21 | }, 22 | }; 23 | } 24 | 25 | export * from "./_namespaces/lpc.js"; 26 | -------------------------------------------------------------------------------- /server/src/lpcserver/MarkdownString.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | /* 6 | * Copyright (C) 2022 TypeFox and others. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 10 | */ 11 | 12 | import type * as lsp from 'vscode-languageserver/node.js'; 13 | 14 | export const enum MarkdownStringTextNewlineStyle { 15 | Paragraph = 0, 16 | Break = 1, 17 | } 18 | 19 | export class MarkdownString { 20 | constructor(public value = '') {} 21 | 22 | appendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle = MarkdownStringTextNewlineStyle.Paragraph): MarkdownString { 23 | this.value += escapeMarkdownSyntaxTokens(value) 24 | .replace(/([ \t]+)/g, (_match, g1) => ' '.repeat(g1.length)) 25 | .replace(/>/gm, '\\>') 26 | .replace(/\n/g, newlineStyle === MarkdownStringTextNewlineStyle.Break ? '\\\n' : '\n\n'); 27 | 28 | return this; 29 | } 30 | 31 | appendMarkdown(value: string): MarkdownString { 32 | this.value += value; 33 | return this; 34 | } 35 | 36 | appendCodeblock(langId: string, code: string): MarkdownString { 37 | this.value += '\n```'; 38 | this.value += langId; 39 | this.value += '\n'; 40 | this.value += code; 41 | this.value += '\n```\n'; 42 | return this; 43 | } 44 | 45 | toMarkupContent(): lsp.MarkupContent { 46 | return { 47 | kind: 'markdown', 48 | value: this.value, 49 | }; 50 | } 51 | } 52 | 53 | export function escapeMarkdownSyntaxTokens(text: string): string { 54 | // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash 55 | return text.replace(/[\\`*_{}[\]()#+\-!]/g, '\\$&'); 56 | } 57 | -------------------------------------------------------------------------------- /server/src/lpcserver/document.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlchmura/lpc-language-server/040d1d1edc7bc5a29988f63fc314cf66dff3a839/server/src/lpcserver/document.ts -------------------------------------------------------------------------------- /server/src/lpcserver/nodeServer.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import * as lpc from "../lpc/lpc.js"; 3 | import { noop } from "../lpc/lpc.js"; 4 | 5 | export class Logger implements Logger { 6 | private seq = 0; 7 | private inGroup = false; 8 | private firstInGroup = true; 9 | private fd = -1; 10 | constructor( 11 | private readonly logFilename: string, 12 | private readonly traceToConsole: boolean, 13 | private readonly level: lpc.server.LogLevel, 14 | ) { 15 | if (this.logFilename) { 16 | try { 17 | this.fd = fs.openSync(this.logFilename, "w"); 18 | } 19 | catch (_) { 20 | // swallow the error and keep logging disabled if file cannot be opened 21 | } 22 | } 23 | } 24 | static padStringRight(str: string, padding: string) { 25 | return (str + padding).slice(0, padding.length); 26 | } 27 | close() { 28 | if (this.fd >= 0) { 29 | fs.close(this.fd, noop); 30 | this.fd = -1; 31 | } 32 | } 33 | getLogFileName(): string | undefined { 34 | return this.logFilename; 35 | } 36 | perftrc(s: string) { 37 | this.msg(s, lpc.server.Msg.Perf); 38 | } 39 | info(s: string) { 40 | this.msg(s, lpc.server.Msg.Info); 41 | } 42 | err(s: string) { 43 | this.msg(s, lpc.server.Msg.Err); 44 | } 45 | startGroup() { 46 | this.inGroup = true; 47 | this.firstInGroup = true; 48 | } 49 | endGroup() { 50 | this.inGroup = false; 51 | } 52 | loggingEnabled() { 53 | return !!this.logFilename || this.traceToConsole; 54 | } 55 | hasLevel(level: lpc.server.LogLevel) { 56 | return this.loggingEnabled() && this.level >= level; 57 | } 58 | msg(s: string, type: lpc.server.Msg = lpc.server.Msg.Err) { 59 | if (!this.canWrite()) return; 60 | 61 | s = `[${lpc.server.nowString()}] ${s}\n`; 62 | if (!this.inGroup || this.firstInGroup) { 63 | const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " "); 64 | s = prefix + s; 65 | } 66 | this.write(s, type); 67 | if (!this.inGroup) { 68 | this.seq++; 69 | } 70 | } 71 | protected canWrite() { 72 | return this.fd >= 0 || this.traceToConsole; 73 | } 74 | protected write(s: string, _type: lpc.server.Msg) { 75 | if (this.fd >= 0) { 76 | const buf = Buffer.from(s); 77 | // eslint-disable-next-line no-restricted-syntax 78 | fs.writeSync(this.fd, buf, 0, buf.length, /*position*/ null); 79 | } 80 | if (this.traceToConsole) { 81 | console.debug(s); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /server/src/lpcserver/openJsDocLink.ts: -------------------------------------------------------------------------------- 1 | export interface OpenJsDocLinkCommand_Args { 2 | readonly file: { 3 | readonly scheme: string; 4 | readonly authority?: string; 5 | readonly path?: string; 6 | readonly query?: string; 7 | readonly fragment?: string; 8 | }; 9 | readonly position: { 10 | readonly line: number; 11 | readonly character: number; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /server/src/lpcserver/previewer.ts: -------------------------------------------------------------------------------- 1 | import { MarkdownString } from "./MarkdownString"; 2 | import * as lpc from "../lpc/lpc.js"; 3 | import { IFilePathToResourceConverter, asPlainTextWithLinks, tagsToMarkdown } from "./textRendering"; 4 | 5 | -------------------------------------------------------------------------------- /server/src/lpcserver/protocol.const.ts: -------------------------------------------------------------------------------- 1 | export class Kind { 2 | public static readonly alias = 'alias'; 3 | public static readonly callSignature = 'call'; 4 | public static readonly class = 'class'; 5 | public static readonly const = 'const'; 6 | public static readonly constructorImplementation = 'constructor'; 7 | public static readonly constructSignature = 'construct'; 8 | public static readonly directory = 'directory'; 9 | public static readonly enum = 'enum'; 10 | public static readonly define = 'define'; 11 | public static readonly enumMember = 'enum member'; 12 | public static readonly externalModuleName = 'external module name'; 13 | public static readonly function = 'function'; 14 | public static readonly indexSignature = 'index'; 15 | public static readonly interface = 'interface'; 16 | public static readonly keyword = 'keyword'; 17 | public static readonly let = 'let'; 18 | public static readonly localFunction = 'local function'; 19 | public static readonly localVariable = 'local var'; 20 | public static readonly method = 'method'; 21 | public static readonly memberGetAccessor = 'getter'; 22 | public static readonly memberSetAccessor = 'setter'; 23 | public static readonly memberVariable = 'property'; 24 | public static readonly module = 'module'; 25 | public static readonly primitiveType = 'primitive type'; 26 | public static readonly script = 'script'; 27 | public static readonly type = 'type'; 28 | public static readonly variable = 'var'; 29 | public static readonly warning = 'warning'; 30 | public static readonly string = 'string'; 31 | public static readonly parameter = 'parameter'; 32 | public static readonly typeParameter = 'type parameter'; 33 | } 34 | 35 | 36 | export class KindModifiers { 37 | public static readonly optional = 'optional'; 38 | public static readonly deprecated = 'deprecated'; 39 | public static readonly color = 'color'; 40 | 41 | public static readonly dtsFile = '.d.ts'; 42 | public static readonly tsFile = '.ts'; 43 | public static readonly tsxFile = '.tsx'; 44 | public static readonly jsFile = '.js'; 45 | public static readonly jsxFile = '.jsx'; 46 | public static readonly jsonFile = '.json'; 47 | 48 | public static readonly fileExtensionKindModifiers = [ 49 | KindModifiers.dtsFile, 50 | KindModifiers.tsFile, 51 | KindModifiers.tsxFile, 52 | KindModifiers.jsFile, 53 | KindModifiers.jsxFile, 54 | KindModifiers.jsonFile, 55 | ]; 56 | } 57 | -------------------------------------------------------------------------------- /server/src/server.ts: -------------------------------------------------------------------------------- 1 | import { createConnection, ProposedFeatures } from "vscode-languageserver/node"; 2 | import {start} from "./lpcserver/server.js"; 3 | 4 | console.info("Starting LPC Language Server"); 5 | process.title = "lpc-language-server-2"; 6 | 7 | // Create a connection for the server, using Node's IPC as a transport. 8 | const connection = createConnection(ProposedFeatures.all); 9 | // console.log = connection.console.log.bind(connection.console.log); 10 | // console.error = connection.console.error.bind(connection.console.error); 11 | 12 | start(connection, require("os").platform(), process.argv); 13 | -------------------------------------------------------------------------------- /server/src/server/_namespaces/lpc.server.protocol.ts: -------------------------------------------------------------------------------- 1 | export * from "../protocol.js"; 2 | -------------------------------------------------------------------------------- /server/src/server/_namespaces/lpc.server.ts: -------------------------------------------------------------------------------- 1 | export * from "../types.js"; 2 | export * from "../utilitiesPublic.js"; 3 | export * from "../utilities.js"; 4 | import * as protocol from "./lpc.server.protocol.js"; 5 | export { protocol }; 6 | export * from "../scriptInfo.js"; 7 | export * from "../project.js"; 8 | export * from "../editorServices.js"; 9 | export * from "../session.js"; 10 | export * from "../scriptVersionCache.js"; -------------------------------------------------------------------------------- /server/src/server/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | export * from "../../compiler/_namespaces/lpc.js"; 2 | export * from "../../services/_namespaces/lpc.js"; 3 | import * as server from "./lpc.server.js"; 4 | export { server }; 5 | -------------------------------------------------------------------------------- /server/src/server/types.ts: -------------------------------------------------------------------------------- 1 | import { DirectoryWatcherCallback, FileWatcher, FileWatcherCallback, ModuleImportResult, System, WatchOptions } from "./_namespaces/lpc"; 2 | 3 | 4 | export interface ServerHost extends System { 5 | watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; 6 | watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; 7 | preferNonRecursiveWatch?: boolean; 8 | setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; 9 | clearTimeout(timeoutId: any): void; 10 | setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; 11 | clearImmediate(timeoutId: any): void; 12 | gc?(): void; 13 | trace?(s: string): void; 14 | require?(initialPath: string, moduleName: string): ModuleImportResult; 15 | /** @internal */ 16 | importPlugin?(root: string, moduleName: string): Promise; 17 | } 18 | 19 | export interface SymbolDisplayPart { 20 | /** 21 | * Text of an item describing the symbol. 22 | */ 23 | text: string; 24 | /** 25 | * The symbol's kind (such as 'className' or 'parameterName' or plain 'text'). 26 | */ 27 | kind: string; 28 | } -------------------------------------------------------------------------------- /server/src/server/utilitiesPublic.ts: -------------------------------------------------------------------------------- 1 | import { createSortedArray, getNormalizedAbsolutePath, isRootedDiskPath, normalizePath, Path, SortedArray, SortedReadonlyArray } from "./_namespaces/lpc"; 2 | import { Project } from "./_namespaces/lpc.server"; 3 | 4 | export enum LogLevel { 5 | terse, 6 | normal, 7 | requestTime, 8 | verbose, 9 | } 10 | 11 | export interface Logger { 12 | close(): void; 13 | hasLevel(level: LogLevel): boolean; 14 | loggingEnabled(): boolean; 15 | perftrc(s: string): void; 16 | info(s: string): void; 17 | startGroup(): void; 18 | endGroup(): void; 19 | msg(s: string, type?: Msg): void; 20 | getLogFileName(): string | undefined; 21 | /** @internal*/ isTestLogger?: boolean; 22 | } 23 | 24 | // TODO: Use a const enum (https://github.com/Microsoft/TypeScript/issues/16804) 25 | export enum Msg { 26 | Err = "Err", 27 | Info = "Info", 28 | Perf = "Perf", 29 | } 30 | 31 | export type NormalizedPath = string & { __normalizedPathTag: any; }; 32 | 33 | export const emptyArray: SortedReadonlyArray = createSortedArray(); 34 | 35 | export function normalizedPathToPath(normalizedPath: NormalizedPath, currentDirectory: string, getCanonicalFileName: (f: string) => string): Path { 36 | const f = isRootedDiskPath(normalizedPath) ? normalizedPath : getNormalizedAbsolutePath(normalizedPath, currentDirectory); 37 | return getCanonicalFileName(f) as Path; 38 | } 39 | 40 | export function toNormalizedPath(fileName: string): NormalizedPath { 41 | return normalizePath(fileName) as NormalizedPath; 42 | } 43 | 44 | export namespace Errors { 45 | export function ThrowNoProject(): never { 46 | throw new Error("No Project."); 47 | } 48 | export function ThrowProjectLanguageServiceDisabled(): never { 49 | throw new Error("The project's language service is disabled."); 50 | } 51 | export function ThrowProjectDoesNotContainDocument(fileName: string, project: Project): never { 52 | throw new Error(`Project '${project.getProjectName()}' does not contain document '${fileName}'`); 53 | } 54 | } 55 | 56 | export function asNormalizedPath(fileName: string): NormalizedPath { 57 | return fileName as NormalizedPath; 58 | } 59 | 60 | /** @internal */ 61 | export function makeAuxiliaryProjectName(counter: number): string { 62 | return `/dev/null/auxiliaryProject${counter}*`; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.Completions.StringCompletions.ts: -------------------------------------------------------------------------------- 1 | export * from "../stringCompletions.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.Completions.ts: -------------------------------------------------------------------------------- 1 | export * from "../completions.js"; 2 | import * as StringCompletions from "./lpc.Completions.StringCompletions.js"; 3 | export { StringCompletions }; 4 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.FindAllReferences.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export * from "../importTracker.js"; 4 | export * from "../findAllReferences.js"; 5 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.GoToDefinition.ts: -------------------------------------------------------------------------------- 1 | 2 | export * from "../goToDefinition.js"; 3 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.JsDoc.ts: -------------------------------------------------------------------------------- 1 | export * from "../jsDoc.js"; 2 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.NavigationBar.ts: -------------------------------------------------------------------------------- 1 | export * from "../navigationBar.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.Rename.ts: -------------------------------------------------------------------------------- 1 | export * from "../rename.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.SignatureHelp.ts: -------------------------------------------------------------------------------- 1 | export * from "../signatureHelp.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.SymbolDisplay.ts: -------------------------------------------------------------------------------- 1 | export * from "../symbolDisplay.js"; 2 | -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.codefix.ts: -------------------------------------------------------------------------------- 1 | export * from "../codefixes/importFixes.js"; 2 | export * from "../codefixes/helpers.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.formatting.ts: -------------------------------------------------------------------------------- 1 | export * from "../formatting/formattingContext.js"; 2 | export * from "../formatting/rule.js"; 3 | export * from "../formatting/rules.js"; 4 | export * from "../formatting/rulesMap.js"; 5 | export * from "../formatting/formatting.js"; 6 | export * from "../formatting/smartIndenter.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.textChanges.ts: -------------------------------------------------------------------------------- 1 | export * from "../textChanges.js"; -------------------------------------------------------------------------------- /server/src/services/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | export * from "../../compiler/_namespaces/lpc.js"; 2 | export * from "../types.js"; 3 | export * from "../utilities.js"; 4 | export * from "../exportInfoMap.js"; 5 | export * from "../documentRegistry.js"; 6 | export * from "../sourcemaps.js"; 7 | export * from "../services.js"; 8 | 9 | import * as Completions from "./lpc.Completions.js"; 10 | export { Completions }; 11 | import * as FindAllReferences from "./lpc.FindAllReferences.js"; 12 | export { FindAllReferences }; 13 | import * as GoToDefinition from "./lpc.GoToDefinition.js"; 14 | export { GoToDefinition }; 15 | import * as Rename from "./lpc.Rename.js"; 16 | export { Rename } 17 | import * as SymbolDisplay from "./lpc.SymbolDisplay.js"; 18 | export { SymbolDisplay }; 19 | import * as formatting from "./lpc.formatting.js"; 20 | export { formatting }; 21 | import * as JsDoc from "./lpc.JsDoc.js"; 22 | export { JsDoc }; 23 | import * as textChanges from "./lpc.textChanges.js"; 24 | export { textChanges }; 25 | import * as codefix from "./lpc.codefix.js"; 26 | export { codefix }; 27 | import * as SignatureHelp from "./lpc.SignatureHelp.js"; 28 | export { SignatureHelp }; 29 | import * as NavigationBar from "./lpc.NavigationBar.js"; 30 | export { NavigationBar }; 31 | -------------------------------------------------------------------------------- /server/src/services/codefixes/helpers.ts: -------------------------------------------------------------------------------- 1 | import { getModuleSpecifierResolverHost, LanguageServiceHost, Program, SymbolTracker } from "../_namespaces/lpc"; 2 | 3 | /** @internal */ 4 | export function getNoopSymbolTrackerWithResolver(context: TypeConstructionContext): SymbolTracker { 5 | return { 6 | trackSymbol: () => false, 7 | moduleResolverHost: getModuleSpecifierResolverHost(context.program, context.host), 8 | }; 9 | } 10 | 11 | 12 | /** @internal */ 13 | export interface TypeConstructionContext { 14 | program: Program; 15 | host: LanguageServiceHost; 16 | } -------------------------------------------------------------------------------- /server/src/services/formatting/rule.ts: -------------------------------------------------------------------------------- 1 | import { FormattingContext } from "../_namespaces/lpc.formatting.js"; 2 | import { 3 | emptyArray, 4 | SyntaxKind, 5 | } from "../_namespaces/lpc.js"; 6 | 7 | /** @internal */ 8 | export interface Rule { 9 | // Used for debugging to identify each rule based on the property name it's assigned to. 10 | readonly debugName: string; 11 | readonly context: readonly ContextPredicate[]; 12 | readonly action: RuleAction; 13 | readonly flags: RuleFlags; 14 | } 15 | 16 | /** @internal */ 17 | export type ContextPredicate = (context: FormattingContext) => boolean; 18 | /** @internal */ 19 | export const anyContext: readonly ContextPredicate[] = emptyArray; 20 | 21 | // dprint-ignore 22 | /** @internal */ 23 | export const enum RuleAction { 24 | None = 0, 25 | StopProcessingSpaceActions = 1 << 0, 26 | StopProcessingTokenActions = 1 << 1, 27 | InsertSpace = 1 << 2, 28 | InsertNewLine = 1 << 3, 29 | DeleteSpace = 1 << 4, 30 | DeleteToken = 1 << 5, 31 | InsertTrailingSemicolon = 1 << 6, 32 | 33 | StopAction = StopProcessingSpaceActions | StopProcessingTokenActions, 34 | ModifySpaceAction = InsertSpace | InsertNewLine | DeleteSpace, 35 | ModifyTokenAction = DeleteToken | InsertTrailingSemicolon, 36 | } 37 | 38 | /** @internal */ 39 | export const enum RuleFlags { 40 | None, 41 | CanDeleteNewLines, 42 | } 43 | 44 | /** @internal */ 45 | export interface TokenRange { 46 | readonly tokens: readonly SyntaxKind[]; 47 | readonly isSpecific: boolean; 48 | } 49 | -------------------------------------------------------------------------------- /server/src/tests/TestFileHandler.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import { IFileHandler, LoadImportResult } from "../lpc/lpc.js"; 4 | 5 | export class TestFileHandler implements IFileHandler { 6 | public includes: string[] = []; 7 | 8 | loadInclude(sourceFilename: string, filename: string): LoadImportResult { 9 | const f = path.join( 10 | process.cwd(), 11 | "server/src/tests/test-assets/", 12 | filename 13 | ); 14 | this.includes.push(f); 15 | return { 16 | uri: f, 17 | source: fs.readFileSync(f, "utf8").toString(), 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/src/tests/_namespaces/lpc.server.ts: -------------------------------------------------------------------------------- 1 | /* Generated file to emulate the lpc.server namespace. */ 2 | 3 | export * from "../../server/_namespaces/lpc.server.js"; -------------------------------------------------------------------------------- /server/src/tests/_namespaces/lpc.ts: -------------------------------------------------------------------------------- 1 | /* Generated file to emulate the ts namespace. */ 2 | 3 | export * from "../../compiler/_namespaces/lpc.js"; 4 | export * from "../../services/_namespaces/lpc.js"; 5 | export * from "../../server/_namespaces/lpc.js"; 6 | export * from "../../harness/harnessIO.js"; 7 | import * as server from "./lpc.server.js"; 8 | export { server }; 9 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/arity1.c: -------------------------------------------------------------------------------- 1 | 2 | varargs string tp(int foo, int bar) { return ""; } 3 | 4 | test() { 5 | string x = tp(); 6 | string y = tp(1); 7 | string z = tp(1,2); 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/arity2.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | string tp(int foo, int bar) { return ""; } 3 | 4 | test() { 5 | string x = tp(); 6 | string y = tp(1); 7 | string z = tp(1,2); 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array1.c: -------------------------------------------------------------------------------- 1 | // array types and literals 2 | string *arr = ({ "a", "b", "c" }); 3 | string *arr2 = ({ }); 4 | 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array2.c: -------------------------------------------------------------------------------- 1 | 2 | string* arr = ({ "a", "b", "c" }); 3 | test() { 4 | arr += ({ "d" }); 5 | // should always allow subtracting 0 elements 6 | arr -= ({ 0 }); 7 | arr -= ({ "a" }); 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array3.c: -------------------------------------------------------------------------------- 1 | 2 | object *arr = ({}); 3 | test() { 4 | object o; 5 | arr = arr + ({ o }); 6 | arr -= ({ 0 }); 7 | arr = arr - ({ 0 }); 8 | arr = arr - ({ o }); 9 | arr = arr | ({ o }); 10 | arr = arr & ({ o }); 11 | arr |= ({ o }); 12 | arr &= ({ o }); 13 | arr = arr | arr; 14 | arr = arr & arr; 15 | arr |= arr; 16 | arr &= arr; 17 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array4.c: -------------------------------------------------------------------------------- 1 | test() { 2 | 3 | string **arr; 4 | string **arr2 = ({ ({ "a", "b" }), ({ "c", "d" }) }); 5 | string ***arr3; 6 | string ****arr4; 7 | 8 | } 9 | 10 | // tests multi-dimension arrays -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array5.c: -------------------------------------------------------------------------------- 1 | test() { 2 | 3 | string *arr = ( { "a", "b" } ); 4 | 5 | } 6 | 7 | // allow whitespace in array initializer -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array6.c: -------------------------------------------------------------------------------- 1 | * test() { 2 | 3 | string *arr = ( { "a", "b" } ); 4 | return arr; 5 | 6 | } 7 | 8 | // declaration can have an array indicator without a type -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/array7.c: -------------------------------------------------------------------------------- 1 | * test() { 2 | 3 | string *arr = ( { "a", "b" } ); 4 | return arr; 5 | 6 | } 7 | 8 | test2() { 9 | int i = test(); // this should fail because because array cannot be assigned to int 10 | } 11 | 12 | // @errors: 1 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignment1.c: -------------------------------------------------------------------------------- 1 | 2 | int x = 1; 3 | string y = ""; 4 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignment2.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | // reports simple type errors 3 | string a = 123; 4 | int b = "123"; 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignment3.c: -------------------------------------------------------------------------------- 1 | // allows 0 assignment to any type 2 | string foo = 0; 3 | int bar = 0; 4 | object baz = 0; 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignment4.c: -------------------------------------------------------------------------------- 1 | // assign binary expression to a variable 2 | test() { 3 | 4 | string foo = "foo"; 5 | string bar = "bar"; 6 | object o; 7 | 8 | // @lpc-expect-error: the result of the binary expression is a string 9 | int result = o && foo && bar; 10 | } 11 | 12 | /** 13 | * This checks that the result of a binary expression is not implicitly converted to an int. 14 | * The expression `o && foo && bar` evaluates to a string, and assigning it to 15 | * an int variable should raise an error. 16 | */ 17 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignment5.c: -------------------------------------------------------------------------------- 1 | // assign binary expression to a variable 2 | test() { 3 | string foo = "foo"; 4 | string bar = "bar"; 5 | object o; 6 | 7 | int result = !!(o && foo && bar); 8 | } 9 | 10 | /** 11 | * This is a valid way of using a binary expression in an assignment. 12 | * The expression `o && foo && bar` evaluates to a string, and the `!!` operator 13 | * converts it to an int, which is then assigned to the `result` variable 14 | * without raising an error. 15 | */ 16 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/assignmentArraySpread.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | 3 | void testArrayWithSpread() { 4 | int *arr = ({ 1, 2, 3 }); 5 | int *arr2 = ({ 1, arr... }); 6 | 7 | int elem = 1; 8 | int *arr3 = ({arr..., elem}); 9 | } 10 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/atBlock1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | testStringShortcut() { 3 | write(@STR 4 | This is a string 5 | STR 6 | ); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/atBlock2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // test format shortcut - array form 3 | test() { 4 | string *arr = 5 | @@ARR 6 | This is a 7 | multiline 8 | string 9 | ARR 10 | ; 11 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/atBlock3.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | void do_tests() { 3 | mixed *a; 4 | string s = @END 5 | xxx 6 | yyy 7 | END; 8 | 9 | a = @@END 10 | xxx 11 | yyy 12 | END; 13 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/atBlock4.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 1 3 | // this should report an error but not crash the parser 4 | void do_tests() { 5 | string s = @ 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/atBlock5.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 1 3 | // this should report an error but not crash the parser 4 | void do_tests() { 5 | string s = @@ 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/badBreak.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | test() { 3 | break; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/badContinue.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | test() { 3 | continue; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/badInitializer.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | int x += 1; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/badLocalInit.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | void foo() { 3 | int x += 1; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/badSwitch.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | fn() { 3 | int i; 4 | switch (i) { 5 | default: 6 | return 1; 7 | default: 8 | return 2; 9 | } 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/buffer1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | buffer b; 3 | test() { 4 | buffer result = b + b; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/buffer2.c: -------------------------------------------------------------------------------- 1 | 2 | string buffer = "abc"; 3 | 4 | string test(string buffer) { 5 | return buffer; 6 | } 7 | 8 | // buffer is not a reserved word in LD 9 | 10 | // @driver: ldmud -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/bytes1.c: -------------------------------------------------------------------------------- 1 | bytes b; 2 | 3 | test() { 4 | bytes result = b + b; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/callOther1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int i = "object.c"->query_number(); 3 | } 4 | 5 | // @files: object.c 6 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/callOther2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object o = clone_object("object.c"); 3 | int i = o->query_number(); 4 | } 5 | 6 | // @files: object.c 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/callOther3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | /** @type {"object.c"*} */ 3 | object *o = ({}); 4 | 5 | // call other on an array is legal in fluffos 6 | o->query_number(); 7 | } 8 | 9 | // @driver: fluffos 10 | // @files: object.c 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/callOther4.c: -------------------------------------------------------------------------------- 1 | test() { 2 | /** @type {"object.c"*} */ 3 | object *o = ({}); 4 | 5 | // call other on an array is legal in fluffos 6 | string fn = "query_number"; 7 | o->(fn)(); 8 | } 9 | 10 | // @driver: fluffos 11 | // @files: object.c 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/callOther5.c: -------------------------------------------------------------------------------- 1 | test() { 2 | /** @type {"object.c"*} */ 3 | object *o = ({}); 4 | 5 | // call other on an array is legal in fluffos 6 | string fn = "query_number"; 7 | o->(fn2)(); 8 | } 9 | 10 | /* 11 | * fn2 should report as not able to resolve 12 | */ 13 | 14 | // @driver: fluffos 15 | // @files: object.c 16 | // @errors: 1 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchBlock.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | test() { 3 | mixed err = catch { 4 | // stuff 5 | }; 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchBlock2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | test() { 3 | catch { 4 | int foo = 1; 5 | } 6 | return foo; 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchBlock3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string x="1"; 3 | catch { 4 | int foo = x; 5 | } 6 | } 7 | 8 | // @driver: fluffos 9 | // @errors: 1 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchBlock4.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object o = clone_object("object.c"); 3 | catch(o->query_number(); publish); 4 | } 5 | 6 | // catch statements can have modifiers in LD 7 | 8 | // @files: object.c 9 | // @driver: ldmud 10 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchBlock5.c: -------------------------------------------------------------------------------- 1 | int moo() { 2 | string err; 3 | 4 | err = catch { 5 | return 1; 6 | }; 7 | 8 | return 2; 9 | } 10 | 11 | /** 12 | * This tests https://github.com/jlchmura/lpc-language-server/issues/242 13 | * current flow node should not be set to unreachable when a return has 14 | * a catch ancestor. 15 | * 16 | * In other words, `return 2` should not be marked as unreachable. 17 | */ 18 | 19 | // @driver: fluffos 20 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchExpr1.c: -------------------------------------------------------------------------------- 1 | void testCatches() { 2 | object o = clone_object("object.c"); 3 | if (err=catch(o->query_number())) { 4 | write("error"); 5 | } 6 | } 7 | 8 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchStmt1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string* arr; 3 | catch(call_other("foo", arr)); 4 | } 5 | 6 | // @driver: fluffos 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/catchStmt2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | // @lpc-expect-error: arrNot is not defined 3 | catch(call_other("foo", arrNot)); 4 | } 5 | 6 | // @driver: fluffos 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/charLiteral1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int a = 'a'; 3 | int b = '1'; 4 | // this is legal in LD 5 | int c = '''; 6 | } 7 | 8 | /** 9 | * tests issue #276 10 | */ 11 | // @driver: ldmud 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/class1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // fluffos new class syntax 3 | class Test { 4 | int i; 5 | } 6 | 7 | test() { 8 | foo = new(class Test); 9 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/class2.c: -------------------------------------------------------------------------------- 1 | // ldmud should fail on class syntax 2 | test() { 3 | foo = new(class Test); 4 | } 5 | 6 | // @driver: ldmud 7 | // @errors: 4 8 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/class3.c: -------------------------------------------------------------------------------- 1 | class equipped { 2 | string name; 3 | int time, uptime; 4 | string eq_file; 5 | string primary; 6 | int *guilds; 7 | int *stats; 8 | int wc; 9 | int dr, dt, ac; 10 | int weight, value; 11 | string *armor_slots; 12 | } 13 | 14 | test() { 15 | class equipped eq; 16 | int j = eq->dt; 17 | } 18 | 19 | /** 20 | * Class property declarations can be a list. (e.g. dr, dt, ac) 21 | */ 22 | 23 | // @driver: fluffos 24 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/class4.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string class = "abc"; 3 | } 4 | 5 | test2(int class) { 6 | 7 | } 8 | 9 | /** 10 | * `class` is not a reserved word in LD 11 | */ 12 | 13 | // @driver: ldmud 14 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/clone_object1.c: -------------------------------------------------------------------------------- 1 | // @files: object.c,std.c 2 | test() { 3 | object o = clone_object("object.c"); 4 | int i = o->query_number(); 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/clone_object2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object o = clone_object("object.c"); 3 | // this should fail because query_number returns an int 4 | string i = o->query_number(); 5 | } 6 | // @errors: 1 7 | // @files: object.c,std.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int *arr = ({1, 2, 3}); 3 | int *i = filter(arr, (: $1 > 1 :)); 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure2.c: -------------------------------------------------------------------------------- 1 | // closure open tokens can have trivia inside them 2 | test() { 3 | int *arr = ({1, 2, 3}); 4 | int *i = filter(arr, ( 5 | : $1 > 1 6 | :)); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure3.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | test() { 3 | int *arr = ({1, 2, 3}); 4 | int *i = filter(arr, (: $1 > foo() :)); // foo is not defined 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure4.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // parse the evalute expressions in closures 3 | // (*$(foo)) and $(foo) 4 | private object *apply_custom_filter(object *obs, function f, object tp) { 5 | return filter(obs, (: (*$(f))($1, $(tp)) :)) ; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure5.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 1 3 | // parse the evalute expressions in closures 4 | // (*$(foo)) and $(foo) 5 | private object *filter_by_id(object *obs, string arg) { 6 | return filter(obs, (: $(arg2) :)) ; // arg2 not found 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure6.c: -------------------------------------------------------------------------------- 1 | int setToColor(string color) { return 1; } 2 | 3 | test() { 4 | string *colors = ({ "red", "green", "blue" }); 5 | int *i; 6 | 7 | i = map(colors, (: setToColor :)); 8 | } 9 | 10 | /** 11 | * This tests the return type of an inline closure set to do a identifier 12 | * which resolves to a function. In this case, the closure return type 13 | * should be the same as the function (setToColor) 14 | */ 15 | 16 | // @driver: fluffos -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure7.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string *list; 3 | list = map(list, (: return $1[5..<2]+"h"; :)); 4 | } 5 | 6 | /** 7 | * This tests for #206 https://github.com/jlchmura/lpc-language-server/issues/206 8 | * An inline closure can have a statement, ending with a semicolon 9 | */ 10 | 11 | // @driver: ldmud 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closure8.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string *colors = ({ "red", "green", "blue" }); 3 | string *newColors; 4 | 5 | newColors = map(colors, (: capitalize :)); 6 | } 7 | 8 | /** 9 | * This tests the return type of an inline closure set to do a identifier 10 | * which resolves to a function. In this case, the closure return type 11 | * should be the same as the function (capitalize) 12 | * 13 | * This test is similar to closure6 except that it uses an efun, which will 14 | * have lazy return type resolution. 15 | * 16 | * Tests for https://github.com/jlchmura/lpc-language-server/issues/248 17 | */ 18 | 19 | // @driver: fluffos 20 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closureFuncShortcut1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // function shortcut 3 | private test() { 4 | object ob; 5 | string fun; 6 | function f = (: call_other, ob, fun :); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/closureFuncShortcut2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 2 3 | // function shortcut 4 | private test() { 5 | object ob; 6 | string fun; 7 | // This should fail because call_otherNOT is not a valid function 8 | // and notOb is not defined 9 | function f = (: call_otherNOT, notOb, fun :); 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/commaExpr.c: -------------------------------------------------------------------------------- 1 | // a comma expression with more than 1 comma 2 | void testMultiCommaExpression() { 3 | int i=0; 4 | int *common1 = ({}); 5 | int *common2 = ({}); 6 | int e1 = sizeof(common1) - 1; 7 | int e2 = sizeof(common2) - 1; 8 | 9 | while( i && common1[ e1 ] == common2[ e2 ] ) e1--, e2--, i--; 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations1.c: -------------------------------------------------------------------------------- 1 | int a, b, c; 2 | string x, y, z; 3 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations2.c: -------------------------------------------------------------------------------- 1 | int a=1, b=2, c=3; 2 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations3.c: -------------------------------------------------------------------------------- 1 | int *a, b, *c; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations4.c: -------------------------------------------------------------------------------- 1 | // var decl inside paren exp 2 | int fn() { return 1; } 3 | 4 | void testVarDeclInsideParenExp() { 5 | if ((int i=fn()) != 1) { 6 | write(i); 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations5.c: -------------------------------------------------------------------------------- 1 | // this will get parsed as a binary expression 2 | // but the binder should treat it as a declaration 3 | int fn() { return 1; } 4 | 5 | void test() { 6 | i = fn(); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/declarations6.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | // i will not resolve but should get treated as a declaration 3 | // j will not resolve and show report an error 4 | void test() { 5 | i = j; 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/defaultArgs.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | string query_id() { return 0; } 3 | int id (mixed id: (: "" :)) { 4 | return member_array(id, query_id()) > -1; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/defaultArgs2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 1 3 | // id should error because of string->int assignment 4 | string query_id() { return 0; } 5 | int id (int id: (: "" :)) { 6 | return member_array(id, query_id()) > -1; 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/defaultArgs3.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | string query_id() { return 0; } 3 | int id (string id: (: "" :)) { 4 | return member_array(id, query_id()) > -1; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/define1.c: -------------------------------------------------------------------------------- 1 | #define BAR(x) x 2 | #define FOO(x) BAR(x) 3 | 4 | int a = FOO(1); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/define2.c: -------------------------------------------------------------------------------- 1 | #define 2 | 3 | test() {} 4 | 5 | // @errors: 1 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/define3.c: -------------------------------------------------------------------------------- 1 | string get_name() { return ""; } 2 | string upper(string s) { return s; } 3 | 4 | #define FOO2(x) upper((x)?(x):"") 5 | #define BAR2 (string)upper(FOO2(get_name())) 6 | 7 | test2() { 8 | string name = BAR2; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/defineNull.c: -------------------------------------------------------------------------------- 1 | #define null ([])[0] 2 | 3 | test() { 4 | string j = null; 5 | } 6 | 7 | /** 8 | * This tests https://github.com/jlchmura/lpc-language-server/issues/245 9 | */ 10 | 11 | // @driver: fluffos 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/defineUndefined.c: -------------------------------------------------------------------------------- 1 | #define undefined ([])[0] 2 | 3 | test() { 4 | string j = undefined; 5 | } 6 | 7 | /** 8 | * This tests https://github.com/jlchmura/lpc-language-server/issues/245 9 | */ 10 | 11 | // @driver: fluffos 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/deprecated1.c: -------------------------------------------------------------------------------- 1 | 2 | private deprecated int foo() { return 1; } 3 | 4 | test() { 5 | int j = foo(); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/deprecated2.c: -------------------------------------------------------------------------------- 1 | 2 | private deprecated int foo = 1; 3 | 4 | test() { 5 | int j = foo; 6 | } 7 | 8 | 9 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/deprecated3.c: -------------------------------------------------------------------------------- 1 | 2 | /** @deprecated */ 3 | private int foo() { return 1; } 4 | 5 | test() { 6 | int j = foo(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/doWhile.c: -------------------------------------------------------------------------------- 1 | // do while loop 2 | testDoWhile() { 3 | int i=0; 4 | do { 5 | write(i); 6 | i++; 7 | } while(i<10); 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/efun.fluff.filter.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | 3 | test() { 4 | object* arr; 5 | object* arr2 = filter(arr, (: $1 :)); 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/error1.c: -------------------------------------------------------------------------------- 1 | int test() { 2 | error("This is an error message"); 3 | } 4 | 5 | /** 6 | * this tests the error() call expr handling in the binder 7 | * If successful, error should act as a return point of the function 8 | * Which means it won't report an error that the function doesn't return a value 9 | */ 10 | 11 | // @driver: fluffos -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/error2.c: -------------------------------------------------------------------------------- 1 | int test() { 2 | raise_error("This is an error message"); 3 | } 4 | 5 | /** 6 | * this tests the raise_error() call expr handling in the binder 7 | * If successful, error should act as a return point of the function 8 | * Which means it won't report an error that the function doesn't return a value 9 | */ 10 | 11 | // @driver: ldmud -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/eval1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object mock = new ("object.c"); 3 | expect("foo", (: ({ 4 | // @lpc-expect-error: foo should not exist 5 | assert_equal($(mock)->foo(), 1) 6 | }) :)); 7 | } 8 | 9 | void expect(string lbl, function test) {} 10 | void assert_equal(mixed a, mixed b) {} 11 | 12 | /** 13 | * This test checks the the $(..) eval expression. 14 | * The checker should return the type of mock object, not any. 15 | * 16 | * To test this, we try to call a function that doesn't exist 17 | * and expect and error. This is done specifically because 18 | * if the checker was not working and returned any for $(mock) 19 | * an unresolvable property access would not throw an error. 20 | * 21 | */ 22 | 23 | // @driver: fluffos 24 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/evaluate1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object *obs; 3 | function f; 4 | object tp; 5 | return filter(obs, 6 | (: (*$(f))($1, $(tp)) :) 7 | ); 8 | } 9 | 10 | // @driver: fluffos 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/evaluate2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object *obs; 3 | object tp; 4 | return filter(obs, 5 | (: (*$(f2))($1, $(tp)) :) 6 | ); 7 | } 8 | 9 | /** 10 | * this should fail because f2 is not defined 11 | */ 12 | 13 | // @driver: fluffos 14 | // @errors: 1 15 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/evaluate3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object *obs; 3 | function f; 4 | return filter(obs, 5 | (: (*$(f))($1, $(tp2)) :) 6 | ); 7 | } 8 | 9 | /** 10 | * this should fail because `tp2` is not defined 11 | */ 12 | 13 | // @driver: fluffos 14 | // @errors: 1 15 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/expr1.c: -------------------------------------------------------------------------------- 1 | // various expressios 2 | int fn() { return 1; } 3 | testExpr() { 4 | int i = fn() + 1 * fn() ? 3 / 1 : 4 % 2; 5 | i++; 6 | i += (fn() * 2) + 1; 7 | i >>= 2; 8 | i <<= 2; 9 | i &= 2; 10 | i |= 2; 11 | i ^= 2; 12 | i--; 13 | i = i > 2 ? fn() : -i; 14 | return i; 15 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/expr2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string foo; 3 | if(!foo || foo = "") { 4 | return 0; 5 | } 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/expr3.c: -------------------------------------------------------------------------------- 1 | fn() { return 1; } 2 | test() { 3 | int i; 4 | if(!i = fn()) { 5 | return 0; 6 | } 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/expr4.c: -------------------------------------------------------------------------------- 1 | // if the parser precedence is correct, this should not throw an error 2 | test() { 3 | string sign; 4 | int x; 5 | sign = x < 0 ? "negative " : "positive"; 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/expr5.c: -------------------------------------------------------------------------------- 1 | // unit test for https://github.com/jlchmura/lpc-language-server/issues/104 2 | test(string mode) { 3 | string pathPrivs; 4 | 5 | // if expression parsing is incorrect, then the following will 6 | // be parsed as !(pathPrivs && mode == "read") 7 | // which will cause the mode=="write" test to report an 8 | // unintentional comparison error. 9 | if (!pathPrivs && mode == "read") { 10 | return; 11 | } 12 | 13 | if (mode=="write") { 14 | return; 15 | } 16 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/flowNode1.c: -------------------------------------------------------------------------------- 1 | object to = this_object(); 2 | 3 | test() { 4 | int i = to->foo(); 5 | } 6 | 7 | foo() { 8 | return 1; 9 | } 10 | 11 | // `to` should be recognized as this_object on line 5 12 | // if the flow nodes are not created correctly, the checker 13 | // will stop checking `i` at the function expression -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/flowType1.c: -------------------------------------------------------------------------------- 1 | object o; 2 | 3 | test() { 4 | o = new("object.c"); 5 | o->query_number(); 6 | 7 | fn("", (: ({ 8 | // query_number() should validate correctly here 9 | assert(o->query_number(), "something"), 10 | }) :) ); 11 | } 12 | 13 | fn(string label, function f) {} 14 | assert(mixed left, mixed right) {} 15 | 16 | // @driver: fluffos 17 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/flowType2.c: -------------------------------------------------------------------------------- 1 | varargs void set_dir(string dir, string dest, function fn) {} 2 | 3 | void test(mapping m) { 4 | foreach (mixed dir, mixed dest in m) { 5 | if (arrayp(dir)) { 6 | foreach (string real_dir in dir) { 7 | if (arrayp(dest)) { 8 | set_dir(real_dir, dest...); 9 | } else { 10 | set_dir(real_dir, dest); 11 | } 12 | } 13 | } else if (arrayp(dest)) { 14 | set_dir(dir, dest...); 15 | } else if (stringp(dest)) { 16 | set_dir(dir, dest); 17 | } 18 | } 19 | } 20 | 21 | /** 22 | * this test validates that arrayp assigns the proper array type to a mixed var 23 | * if it does not, the dest... argument will report an error 24 | */ 25 | 26 | // @driver: fluffos 27 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/flowType3.c: -------------------------------------------------------------------------------- 1 | 2 | test() { 3 | object *weapons; 4 | weapons = get_weaps(); 5 | 6 | weapons->query_number(); 7 | foreach(object w in weapons) { 8 | w->query_number(); 9 | } 10 | } 11 | 12 | /** 13 | * @returns {"object.c"*} weapons 14 | */ 15 | object *get_weaps() { 16 | return ({ }); 17 | } 18 | 19 | /** 20 | * This tests https://github.com/jlchmura/lpc-language-server/issues/190 21 | * a generic object array type should take on the flow type in an assignment (line 5) 22 | */ 23 | 24 | 25 | // @driver: fluffos 26 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/fnNoReturn1.c: -------------------------------------------------------------------------------- 1 | // should not report an error 2 | int test() { 3 | return 1; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/fnNoReturn2.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | // this should report a diagnostic because the fn does not return a value 3 | // note the error message is different because this diagnostic is a warning, not an error. 4 | int test() { 5 | 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/fnNoReturn3.c: -------------------------------------------------------------------------------- 1 | // @errors: 0 2 | // @driver: fluffos 3 | // this should not report an error because the fluffos 4 | // `error` efun is marked with a @throws tag 5 | int test() { 6 | error("not implemented"); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/for1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | for(i=0; i<10; i++) { 3 | write(i); 4 | } 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/for2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | for (i=0;;) { 3 | write(i); 4 | i++; 5 | if (i>10) break; 6 | } 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/for3.c: -------------------------------------------------------------------------------- 1 | // for with no init, no condition, no increment 2 | test() { 3 | int i; 4 | for (;;) { 5 | write(i); 6 | i++; 7 | if (i>20) break; 8 | } 9 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/for4.c: -------------------------------------------------------------------------------- 1 | // for with multiple initializers 2 | test() { 3 | int i,j,k; 4 | for (i=0,j=i,k=2; i<10; i++) { 5 | j = i; 6 | k = i; 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach1.c: -------------------------------------------------------------------------------- 1 | void test() { 2 | int *arr = ({ 1, 2, 3 }); 3 | foreach(int i : arr) { 4 | write(i); 5 | } 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach10.c: -------------------------------------------------------------------------------- 1 | 2 | mapping myMap; 3 | test() { 4 | foreach(string key, int value in myMap) { 5 | object o = new(key); 6 | int i = value; 7 | } 8 | } 9 | 10 | test2() { 11 | mapping myMap2 = ([]); 12 | foreach(string key, int value in myMap2) { 13 | object o = new(key); 14 | int i = value; 15 | } 16 | } 17 | 18 | // foreach over an untyped map. key & _value should get their 19 | // types from the variable decl. 20 | 21 | // @driver: fluffos -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach11.c: -------------------------------------------------------------------------------- 1 | test() { 2 | string* functionTypes; 3 | string funcType; 4 | 5 | foreach(funcType in functionTypes) { 6 | 7 | } 8 | } 9 | 10 | /** 11 | * tests for https://github.com/jlchmura/lpc-language-server/issues/243 12 | */ 13 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach2.c: -------------------------------------------------------------------------------- 1 | // foreach over a mapping 2 | void test() { 3 | mapping map = ([ "a": 1, "b": 2, "c": 3 ]); 4 | foreach(string key, int val : map) { 5 | write(key); 6 | write(val); 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int *arr = ({ 1, 2, 3 }); 3 | foreach(int i in arr) { 4 | write(i); 5 | } 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach4.c: -------------------------------------------------------------------------------- 1 | // foreach over a mapping 2 | void test() { 3 | foreach(string key, string val in ([ "a": 1, "b": 2, "c": 3 ])) { 4 | } 5 | } 6 | 7 | /** 8 | * This should produce a type error since the mapping keys are integers and `val` is a string 9 | */ 10 | 11 | // @errors: 1 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach5.c: -------------------------------------------------------------------------------- 1 | // foreach over a mapping 2 | mapping m = ([ "a": 1, "b": 2, "c": 3 ]); 3 | void test() { 4 | foreach(string key, string val in m) { 5 | } 6 | } 7 | 8 | /** 9 | * This should produce a type error since the mapping keys are integers and `val` is a string 10 | */ 11 | 12 | // @errors: 1 13 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach6.c: -------------------------------------------------------------------------------- 1 | // foreach over a mapping with a comma expr on the lhs 2 | void test() { 3 | string key, val; 4 | foreach(key, val in ([ "a": 1, "b": 2, "c": 3 ])) { 5 | } 6 | } 7 | 8 | /** 9 | * This should produce a type error since the mapping keys are integers and `val` is a string 10 | */ 11 | 12 | // @errors: 1 13 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach7.c: -------------------------------------------------------------------------------- 1 | // various valid forms of foreach 2 | mapping m = ([ "a": 1, "b": 2, "c": 3 ]); 3 | void test() { 4 | string key; 5 | int val; 6 | foreach(key, val in ([ "a": 1, "b": 2, "c": 3 ])) { 7 | } 8 | 9 | foreach(string key2, int val2 in ([ "a": 1, "b": 2, "c": 3 ])) { 10 | } 11 | 12 | foreach(string key3, int val3 in m) { 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach8.c: -------------------------------------------------------------------------------- 1 | test() { 2 | /** @type {"object.c"*} */ 3 | object* arr = ({}); 4 | object ob; 5 | foreach(ob in arr) { 6 | ob->query_number(); 7 | } 8 | } 9 | 10 | // @files object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEach9.c: -------------------------------------------------------------------------------- 1 | test() { 2 | /** @type {"object.c"*} */ 3 | object* arr = ({}); 4 | foreach(object ob in arr) { 5 | ob->query_number(); 6 | } 7 | } 8 | 9 | // @files object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEachRef.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | test() { 3 | int *arr = ({1, 2, 3}); 4 | foreach(int ref x in arr) { 5 | x++; 6 | } 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/forEachRef2.c: -------------------------------------------------------------------------------- 1 | 2 | test() { 3 | int *arr = ({1, 2, 3}); 4 | foreach(int x in &arr) { 5 | x++; 6 | } 7 | } 8 | 9 | /* 10 | * LD allows a ref in the foreach loop target 11 | */ 12 | 13 | // @driver: ldmud -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/funcDecl1.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // function params w/ varargs 3 | void fnWithParams(int a, int b, varargs int c) { 4 | write(a); 5 | write(b); 6 | write(c); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/funcDecl2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // function blocks can have semicolon after them 3 | void fn() { 4 | }; 5 | 6 | void fn2() { 7 | 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/funcSignature1.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | // incompatible function signature 4 | int fn(string ar); 5 | int fn(string ar, int a) { 6 | return 1; 7 | } 8 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/funcSignature2.c: -------------------------------------------------------------------------------- 1 | 2 | int fn(string ar); 3 | int fn(string ar) { 4 | return 1; 5 | } 6 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall1.c: -------------------------------------------------------------------------------- 1 | string foo() { return ""; } 2 | string x = foo(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall2.c: -------------------------------------------------------------------------------- 1 | int foo() { return 1; } 2 | int x = foo(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall3.c: -------------------------------------------------------------------------------- 1 | int* foo() { return ({ 1 }); } 2 | int* x = foo(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall4.c: -------------------------------------------------------------------------------- 1 | foo() { return ""; } 2 | bar() { return foo(); } 3 | string x = bar(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall5.c: -------------------------------------------------------------------------------- 1 | string fn() { return ""; } 2 | 3 | // return statement with a comma expression 4 | int main() { 5 | return fn(), 1; 6 | } 7 | 8 | int foo = main(); 9 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/functionCall6.c: -------------------------------------------------------------------------------- 1 | int main(int a) { 2 | return 1; 3 | } 4 | 5 | int test(int main) { 6 | // `main` should correctly resolve to the function, not the `main` parameter 7 | return main(1); 8 | } 9 | 10 | int test2() { 11 | int main = 0; 12 | 13 | // `main` should correctly resolve to the function, not the `main` variable 14 | return main(1); 15 | } 16 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/identifier1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // fluffos allows symbol as an identifier 3 | void testValidIdentifiers() { 4 | string symbol; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/if1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | if (1) { 3 | return 1; 4 | } 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/if2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int foo = 1; 3 | return foo ? "yes" : "no"; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/if3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int foo=1; 3 | int bar=0; 4 | return foo ? "yes" 5 | : bar ? "no" 6 | : "maybe"; 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/ifelse.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int foo=0; 3 | int bar=1; 4 | if (0) { 5 | return 0; 6 | } else if (foo == 1) { 7 | return 0; 8 | } else { 9 | return bar; 10 | } 11 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/in1.c: -------------------------------------------------------------------------------- 1 | string test() { 2 | string in; 3 | in = "abc"; 4 | return in; 5 | } 6 | 7 | /* 8 | * `in` is not a reserved word in LD 9 | */ 10 | 11 | // @driver: ldmud -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/include1.c: -------------------------------------------------------------------------------- 1 | #include "includeFile.h" 2 | 3 | test() { 4 | int i = FOO; 5 | string s = BAR; 6 | } 7 | 8 | // @files: includeFile.h -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/include2.c: -------------------------------------------------------------------------------- 1 | // @files: includeFile.h 2 | 3 | test() {} 4 | 5 | // this include does not have a newline after it, which is legal 6 | // https://github.com/jlchmura/lpc-language-server/issues/184 7 | 8 | #include "includeFile.h" -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/includeFile.h: -------------------------------------------------------------------------------- 1 | 2 | #define FOO 1 3 | #define BAR "bar" 4 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/indexAccess.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // array access 3 | testArrayAccess() { 4 | int *arr = ({ 1, 2, 3 }); 5 | int i = arr[<1]; 6 | i = arr[0..2]; 7 | i = arr[0..<1]; 8 | i = arr[0..]; 9 | i = arr[..<1]; 10 | i = arr[<1..<2]; 11 | return arr[0]; 12 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/indexAccess2.c: -------------------------------------------------------------------------------- 1 | 2 | mapping m = ([ ]); 3 | 4 | test() { 5 | string foo, bar; 6 | if (!m[foo, bar]) { 7 | 8 | } 9 | } 10 | 11 | /** 12 | * multi-arg mapping access inside a prefix unary expression 13 | * should not error 14 | */ -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/inherit1.base1.c: -------------------------------------------------------------------------------- 1 | 2 | inherit "inherit1.base2.c"; 3 | 4 | string query_name() { 5 | isBase2(); 6 | return "inherit1.base1"; 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/inherit1.base2.c: -------------------------------------------------------------------------------- 1 | 2 | string query_name() { 3 | return "inherit1.base2"; 4 | } 5 | 6 | int isBase2() { 7 | return 1; 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/inherit1.c: -------------------------------------------------------------------------------- 1 | inherit "inherit1.base1.c"; 2 | 3 | // make sure members from nested inherits are resolved correctly 4 | 5 | test() { 6 | // base2 comes from base1->base2 7 | int id = isBase2(); 8 | // query_name is defined in both base1 & base2 9 | string name = query_name(); 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/intLiteral1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | int i = 0x1000000000 & 0x1000000000; 3 | i &= 0x1000000000; 4 | // max int 5 | i = 0x7fffffffffffffff; 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/intLiteral2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | test2() { 3 | x = 1234567890123456; 4 | x =0x462d53c8abac0; 5 | x = 0xCAFEBABE; 6 | x = 1234_5678_9012_3456; 7 | x = 0xCAFE_BABE; 8 | x = 0xCA_FE_BA_BE; 9 | x = 3_14_15.9_2_6; 10 | int bin_literal1 = 0b1010; 11 | int bin_literal2 = 0B1101; 12 | int bin_literal3 = 0b01010101; 13 | // Test arithmetic operations with binary literals 14 | int sum_bin_literals = 0b101 + 0B110; 15 | int mul_bin_literals = 0b1010 * 0b1101; 16 | // Test comparison with binary literals 17 | int comp_bin_literals = 0b100 < 0B1100; 18 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/intersectionType.c: -------------------------------------------------------------------------------- 1 | 2 | void test() { 3 | object o = new("object.c"); 4 | 5 | object o2 = /** @type {"object.c" & "object2.c"} */(o); 6 | o2->query_number(); // only exists in object.c 7 | o2->query_name(); // only exists in object2.c 8 | } 9 | 10 | /** 11 | * This test validates intersection types. 12 | * If object & object2 are properly combined, then both call expressions on line 6 & 7 13 | * should be valid. 14 | */ 15 | 16 | // @driver: fluffos 17 | // @files: object.c, object2.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/intersectionTypeIllegal.c: -------------------------------------------------------------------------------- 1 | 2 | void test() { 3 | string & object foo; 4 | } 5 | 6 | /** 7 | * This should produce two parser errors because intersection types 8 | * are only allowed inside LPCDoc 9 | */ 10 | 11 | // @driver: fluffos 12 | // @errors: 2 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/jsDocParam.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | /** 3 | * @param {int} a 4 | * @param {int} b - this doesn't exit 5 | */ 6 | test(int a) { 7 | 8 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lambda1.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | test() { 3 | mixed *wl = filter( 4 | wizlist_info(), 5 | lambda( ({'a}), 6 | ({#'!=, ({#'[, 'a, "NAME"}), "NONAME"}) 7 | ) 8 | ); 9 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpc-ignore.c: -------------------------------------------------------------------------------- 1 | test() { 2 | // @lpc-ignore 3 | int i = "123"; 4 | 5 | string j = 123; 6 | } 7 | 8 | /** 9 | * This file has 2 type errors, but the first should be ignored 10 | * because of the lpc-ignore directive 11 | */ 12 | 13 | // @errors: 1 -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpc-nocheck.c: -------------------------------------------------------------------------------- 1 | // @lpc-nocheck 2 | 3 | test() { 4 | int i = "123"; 5 | string j = 123; 6 | ThisFunDoesNotExist(); 7 | } 8 | 9 | /** 10 | * This file has multiple type errors, but they should be ignored 11 | * because of the lpc-nocheck directive 12 | */ 13 | 14 | // @errors: 0 15 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocParam1.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {"object.c"} o 4 | */ 5 | void test(object o) { 6 | o->query_number(); 7 | } 8 | 9 | /** 10 | * 11 | * @param {"object.c"*} o 12 | */ 13 | void test2(object* o) { 14 | o->query_number(); 15 | } 16 | 17 | /** 18 | * 19 | * @param {"object.c" | string} o 20 | */ 21 | void test3(mixed o) { 22 | if (!stringp(o)) { 23 | o->query_number(); 24 | } 25 | } 26 | 27 | /** 28 | * 29 | * @param {"object.c"* | string} o 30 | */ 31 | void test4(mixed o) { 32 | if (!stringp(o)) { 33 | o->query_number(); 34 | } 35 | } 36 | 37 | // four forms of param type annotations, all of which 38 | // should correctly resolve o to object.c 39 | 40 | // @files: object.c 41 | // @driver: fluffos -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar1.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | // foo is not found 4 | 5 | /** 6 | * @var {string} foo 7 | */ 8 | void test() { 9 | 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar2.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | // foo can't be a local var 4 | string foo; 5 | 6 | /** 7 | * @var {string} foo 8 | */ 9 | void test() { 10 | 11 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar3.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | // var can't be on the same block as another tag 4 | 5 | /** 6 | * @var {string} foo 7 | * @returns something 8 | */ 9 | void test() { 10 | 11 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar4.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | // var must have a name 4 | 5 | /** 6 | * @var {string} 7 | */ 8 | void test() { 9 | 10 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar5.c: -------------------------------------------------------------------------------- 1 | inherit "lpcDocVarTagBase"; 2 | 3 | object notOb; 4 | 5 | /** 6 | * @var {"object.c"} notOb 7 | */ 8 | test() { 9 | 10 | } 11 | 12 | // this test should error because `notOb` does not exist in the inherited file 13 | 14 | // @errors: 1 15 | // @files: lpcDocVarTagBase.c, object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar6.c: -------------------------------------------------------------------------------- 1 | inherit "lpcDocVarTagBase"; 2 | 3 | /** 4 | * @var {"object.c"} baseOb 5 | */ 6 | test() { 7 | int i = baseOb->query_number(); 8 | } 9 | 10 | // @files: lpcDocVarTagBase.c, object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVar7.c: -------------------------------------------------------------------------------- 1 | inherit "lpcDocVarTagBase"; 2 | 3 | /** 4 | * @var {"object.c"} baseOb 5 | * @returns {int} 6 | */ 7 | test() { 8 | int i = baseOb->query_number(); 9 | return i; 10 | } 11 | 12 | // this test should error because var tags are not allowed in the same block as other lpcdoc tags 13 | 14 | // @errors: 1 15 | // @files: lpcDocVarTagBase.c, object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/lpcDocVarTagBase.c: -------------------------------------------------------------------------------- 1 | // base file used in the varTag tests 2 | 3 | object baseOb; 4 | 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/macro1.c: -------------------------------------------------------------------------------- 1 | // simple macro assignment 2 | #define FOO 1 3 | int a = FOO; 4 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/macro2.c: -------------------------------------------------------------------------------- 1 | // nested macro sub 2 | #define BAR(y) y 3 | #define FOO(x) BAR(x) 4 | 5 | int a = FOO(1); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/macro3.c: -------------------------------------------------------------------------------- 1 | #define y add+x; 2 | #define member(x, y) fn(y, x) 3 | 4 | void fn(mixed a, mixed b) {} 5 | 6 | test() { 7 | string *weaptype = ({}); 8 | member(weaptype, "sword"); 9 | } 10 | 11 | /** 12 | * This tests issue 186: https://github.com/jlchmura/lpc-language-server/issues/186 13 | * The macro param `y` should not get substituted by the `add+x` macro. 14 | */ 15 | 16 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/macro4.c: -------------------------------------------------------------------------------- 1 | #define FOO(x, y) x + y 2 | 3 | int *a = FOO( ({ 1, 2, 3 }), ({ 4, 5, 6 }) ); 4 | 5 | /** 6 | * This tests issue 220: https://github.com/jlchmura/lpc-language-server/issues/220 7 | * The parens in the array literal were causing the macro args to parse incorrectly. 8 | */ 9 | 10 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | mapping m = ([ "fd": -1, "error": "Failed to parse response body" ]); 3 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping2.c: -------------------------------------------------------------------------------- 1 | // mapping with keys only 2 | test() { 3 | mapping m = ([ "fd", "error" ]); 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping3.c: -------------------------------------------------------------------------------- 1 | // mapping with multiple values 2 | test() { 3 | mapping m = ([ "fd": 1; 2; 3, "error": 1; 2; 3 ]); 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping4.c: -------------------------------------------------------------------------------- 1 | 2 | test() { 3 | mapping emptyMap = ([ ]); 4 | mapping sizeOnlymap = ([ :10 ]); 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping5.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | // mapping elements should get checked 3 | test() { 4 | string i; 5 | mapping m = ([ "fd": foo(); i=2; ]); // foo doesn't exist and i is the wrong type 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mapping6.c: -------------------------------------------------------------------------------- 1 | private 2 | nosave mapping multiline_lit = ( 3 | ["metal":([128:"steel", 4 | 64:"darksteel", 32:"silver", 16:"gold", 8:"platinum", 4:"titanium", 2:"adamantine", 1:"orichalcum", ]), 5 | "wood":([128:"fir", 64:"pine", 32:"oak", 16:"cedar", 8:"larch", 4:"hemlock", 2:"ebony", 1:"bloodwood", ]), ]); 6 | 7 | // from LIMA: https://github.com/fluffos/lima/blob/dbcef2a9b2919474145e6a533fc434d67f6c7f5a/lib/daemons/crafting_d.c#L31 8 | 9 | // mapping literals can have whitespace (including newlines) between the ( and [ characters 10 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mappingType1.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * mapping with 1 value 5 | * @param {([ string: int ])} foo 6 | */ 7 | test(mapping foo) { 8 | 9 | } 10 | 11 | /** 12 | * mapping with multiplie values 13 | * @param {([ string: int, string ])} foo 14 | */ 15 | test2(mapping foo) { 16 | 17 | } 18 | 19 | /** 20 | * mapping with no values 21 | * @param {([ string ])} foo 22 | */ 23 | test3(mapping foo) { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/mappingType2.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | ([ string: int ]) test() { 4 | return 0; 5 | } 6 | 7 | /** 8 | * mapping type nodes are not allowed outside of lpcdoc 9 | */ 10 | 11 | // @errors: 5 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/missingFunc.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | test() { 3 | int i = missing(); 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/modifiers1.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | // @driver: fluffos 3 | public class Foo { 4 | int x; 5 | int y; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/modifiers2.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | public private test() { 3 | 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/modifiers3.c: -------------------------------------------------------------------------------- 1 | // legal modifiers 2 | public nosave int c; 3 | public nomask test() {} -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject1.c: -------------------------------------------------------------------------------- 1 | test() { 2 | 3 | object "object.c" ob; 4 | ob->query_number(); 5 | 6 | } 7 | 8 | // make sure LDMud named objects are parsed 9 | // and imports resolved 10 | 11 | // @driver: ldmud 12 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | 3 | object "notfound.c" ob; 4 | 5 | } 6 | 7 | // should report an error that the file notfound.c could not be found 8 | 9 | // @driver: ldmud 10 | // @errors: 1 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | 3 | object "notfound.c" ob; 4 | 5 | } 6 | 7 | // named objects should report a parser error in FluffOS 8 | 9 | // @driver: fluffos 10 | // @errors: 3 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject4.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * @param {object "object.c"} o 5 | */ 6 | test(object o) { 7 | 8 | } 9 | 10 | /** 11 | * named object should work in fluffos, but only inside lpcdoc 12 | */ 13 | 14 | // @driver: fluffos 15 | // @files: object.c 16 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject5.c: -------------------------------------------------------------------------------- 1 | #define OBJ "" "object.c" 2 | 3 | /** 4 | * 5 | * @param {object OBJ} o 6 | */ 7 | test(object o) { 8 | 9 | } 10 | 11 | /** 12 | * make sure implied string concat works for named objects 13 | */ 14 | 15 | // @driver: fluffos 16 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/namedObject6.c: -------------------------------------------------------------------------------- 1 | 2 | void test() { 3 | fn()->query_either(); 4 | fn2()->query_either(); 5 | fn3()->query_either(); 6 | } 7 | 8 | /** 9 | * @returns {object "objec" + "t.c" | object "object2.c"} 10 | */ 11 | object fn() { return 0; } 12 | 13 | /** 14 | * @returns {object "objec" "t.c" | object "object2.c"} 15 | */ 16 | object fn2() { return 0; } 17 | 18 | /** 19 | * @returns {object "object.c" | object "object2.c"} 20 | */ 21 | object fn3() { return 0; } 22 | 23 | /** 24 | * this indirectly tests https://github.com/jlchmura/lpc-language-server/issues/251 25 | * 26 | * The parser should not parse the bar token as part of the string literal binary expression 27 | * If parsed correctly, then the result of the function will be a proper union of named object types 28 | * and both of those will have the `query_either` method. 29 | * 30 | */ 31 | 32 | // @files: object.c, object2.c 33 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new1.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | // @driver: fluffos 3 | // clone object using new keyword 4 | // error will be object not found 5 | test() { 6 | object o = new("/std/object"); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | 3 | // struct declaration and instantiation using new keyword 4 | class Foo { 5 | int bar; 6 | } 7 | 8 | test() { 9 | class Foo foo; 10 | foo = new(class Foo); 11 | foo.bar = 1; 12 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new3.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | 3 | // struct declaration and instantiation using new keyword 4 | // with shorthand property assignment 5 | class Foo { 6 | int bar; 7 | } 8 | 9 | test() { 10 | class Foo foo; 11 | foo = new(class Foo, 1); 12 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new4.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | 3 | // struct declaration and instantiation using new keyword 4 | // with named property assignment 5 | class Foo { 6 | int bar; 7 | int baz; 8 | } 9 | 10 | test() { 11 | class Foo foo; 12 | foo = new(class Foo, bar: 1, baz: 2); 13 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new5.c: -------------------------------------------------------------------------------- 1 | class Foo { 2 | string type; 3 | int num; 4 | } 5 | 6 | private class Foo testFn(string type) { 7 | 8 | class Foo msg; 9 | msg = new(class Foo, 10 | type: type, 11 | num: 0 12 | ); 13 | 14 | return msg.type ? msg : 0; 15 | } 16 | 17 | /** 18 | * Test for https://github.com/jlchmura/lpc-language-server/issues/259 19 | * where the parameter `type` was not getting marked as used by the new class expression 20 | */ 21 | 22 | // @driver: fluffos 23 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/new6.c: -------------------------------------------------------------------------------- 1 | class Foo { 2 | string type; 3 | int num; 4 | } 5 | 6 | private class Foo testFn(string type) { 7 | 8 | class Foo msg; 9 | msg = new(class Foo, 10 | type: type, 11 | num: getNum(type) 12 | ); 13 | 14 | return msg.type ? msg : 0; 15 | } 16 | 17 | private string getNum(string type) { return 0; } 18 | 19 | 20 | /** 21 | * Test for https://github.com/jlchmura/lpc-language-server/issues/263 22 | * `num` should error because `getNum` returns a string 23 | */ 24 | 25 | // @driver: fluffos 26 | // @errors: 1 27 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/object.c: -------------------------------------------------------------------------------- 1 | // used by clone object tests 2 | 3 | int query_number() { return 1; } 4 | 5 | int query_either() { return 1; } 6 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/object2.c: -------------------------------------------------------------------------------- 1 | // used by various tests 2 | 3 | string query_name() { return ""; } 4 | 5 | int query_either() { return 1; } 6 | 7 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/operatorBitwise.c: -------------------------------------------------------------------------------- 1 | // bitwise operators 2 | testBitwise() { 3 | int i=0; 4 | return i & 1 | 0; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/operatorDoubleBang.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // various forms of fluff's double-bang operator 3 | reset() { return 0; } 4 | 5 | test() { 6 | int i = 0; 7 | if (!!i) { 8 | write("i is not zero"); 9 | } 10 | int j = !!(i==1); 11 | int k = !!reset(); 12 | int l = !reset(); 13 | int m = !!"something"; 14 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/operatorLogical.c: -------------------------------------------------------------------------------- 1 | // logical operators 2 | testLogical() { 3 | int i=0; 4 | return i && 1 || 0; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/paramRef.c: -------------------------------------------------------------------------------- 1 | 2 | test(int ref *values) { 3 | 4 | } 5 | 6 | test2() { 7 | int *values = ({1, 2, 3}); 8 | test(ref values); 9 | } 10 | 11 | // @driver: fluffos 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/predefined1.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // test predefined driver macros 3 | test() { 4 | int a = MAX_INT; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/predefined2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // @errors: 1 3 | test() { 4 | // this should fail because MAX_FLOAT is not a string 5 | string foo = MAX_FLOAT; 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/preproc_conditional.c: -------------------------------------------------------------------------------- 1 | int i=0; 2 | 3 | #if 0 4 | // this code should not report syntax errors because it is disabled 5 | int FOO = "string"; 6 | ()Invalid Syntax; 7 | #endif -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/preproc_conditional_macro.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | #define FOO 3 | 4 | #ifndef FOO 5 | ()Syntax Error; 6 | #endif 7 | 8 | #ifdef FOO 9 | // this should generate a type error 10 | string i = 123; 11 | #endif -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/return1.c: -------------------------------------------------------------------------------- 1 | 2 | string test() { 3 | return 4 | "foo" 5 | "bar" 6 | "baz"; 7 | } 8 | 9 | /** 10 | * LPC allows the return expression to be on a new line, which is different from 11 | * TS/JS which will apply ASI and return an undefined expression. 12 | * 13 | * This tests for https://github.com/jlchmura/lpc-language-server/issues/261 14 | */ 15 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/string1.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // @errors: 6 3 | // this should fail in LD (fluff allows it) 4 | string s = " 5 | Multieline\n"; 6 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/string2.c: -------------------------------------------------------------------------------- 1 | // @driver: fluffos 2 | // this is allowed in FluffOS 3 | string s = " 4 | Multieline\n"; 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/stringizedIdentifier.c: -------------------------------------------------------------------------------- 1 | #define DEB(x) printf(#x ": %O\n", x) 2 | test() { 3 | DEB("foo"); 4 | } 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/struct1.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // struct declarations 3 | struct Foo { 4 | int i; 5 | string str; 6 | }; 7 | 8 | struct Foo foo; // struct instance 9 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/struct2.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // return structs from functions 3 | struct Foo { 4 | int i; 5 | string str; 6 | }; 7 | 8 | struct Foo foo; 9 | public struct Foo accessStruct(int i) { 10 | foo->i = i; 11 | foo->str = "a"; 12 | return foo; 13 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/struct3.c: -------------------------------------------------------------------------------- 1 | struct container_entry { 2 | string name; 3 | object ob; 4 | }; 5 | 6 | test() { 7 | struct container_entry container = ( "root", player); 8 | struct container_entry *container_stack = ({ }); 9 | } 10 | 11 | // @driver: ldmud 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/struct4.c: -------------------------------------------------------------------------------- 1 | struct note_s { 2 | int foo; 3 | string bar; 4 | }; 5 | 6 | struct note_s issue; 7 | 8 | test(struct note_s nn) { 9 | nn->foo = 1; 10 | } 11 | 12 | /* 13 | * struct as a parameter in LD 14 | */ 15 | 16 | // @driver: ldmud -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/structMemberAccess.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // struct declarations 3 | struct Foo { 4 | int i; 5 | string str; 6 | }; 7 | 8 | struct Foo foo; // struct instance 9 | 10 | int i = foo->i; 11 | string str = foo->str; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/structMemberAccess2.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // struct declarations 3 | struct Foo { 4 | int i; 5 | string str; 6 | }; 7 | 8 | struct Foo foo; // struct instance 9 | 10 | string propName = "str"; 11 | string str = foo->(propName); 12 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/super1.c: -------------------------------------------------------------------------------- 1 | // @errors: 2 2 | // super accessor 3 | // this will fail because this object does not inherit 4 | string query_name() { 5 | string n = "obj"::query_name(); 6 | return ::query_name(); 7 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/super2.c: -------------------------------------------------------------------------------- 1 | // super accessor for an efun 2 | // this is allowed even though this file doesn't inherit anything 3 | void write() { 4 | efun::write(""); 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/switch1.c: -------------------------------------------------------------------------------- 1 | testSwitch(int i) { 2 | switch(i) { 3 | case 1: 4 | return i; 5 | case 2: 6 | case 3: 7 | case 4: 8 | return i+1; 9 | default: 10 | return 3; 11 | } 12 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/switch2.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // switch with ranges 3 | testSwitch(int i) { 4 | int j; 5 | switch(i) { 6 | case 1: 7 | return i; 8 | case 2: 9 | case 3..4: 10 | j++; 11 | break; 12 | // they can also have parens 13 | case (20+1) .. 30: 14 | j+=3; 15 | break; 16 | default: 17 | return 3; 18 | } 19 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/switch3.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | testSwitch(int i) { 3 | switch(i) { 4 | // code block before cases 5 | int j; 6 | case 1: 7 | return 1; 8 | } 9 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/ternary.c: -------------------------------------------------------------------------------- 1 | int i = 1; 2 | int j = i>0 ? 1 : 0; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/thisObject1.c: -------------------------------------------------------------------------------- 1 | // @this_object thisObject1.file2.c 2 | 3 | test() { 4 | int i = this_object()->foo(); 5 | int j = this_object()->bar(); 6 | } 7 | 8 | /* 9 | * both foo & bar should correctly resolve 10 | * `bar` is accessible via this_object even though its protected 11 | */ 12 | 13 | // @files: thisObject1.file2.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/thisObject1.file2.c: -------------------------------------------------------------------------------- 1 | 2 | public foo() { return 1; } 3 | protected bar() { return 1; } 4 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeAssertion1.c: -------------------------------------------------------------------------------- 1 | void test() { 2 | mixed m = "foo"; 3 | string s = ({ string })m; 4 | string s2 = (string)m; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeAssertion2.c: -------------------------------------------------------------------------------- 1 | void fn() { } 2 | 3 | void test() { 4 | ({void})fn(); 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeAssertion3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | mixed *o; 3 | mixed m = ({*})o[0]; 4 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeInference1.c: -------------------------------------------------------------------------------- 1 | // return type of foo() is string 2 | foo() { return ""; } 3 | string bar = foo(); 4 | 5 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeInference2.c: -------------------------------------------------------------------------------- 1 | // return type of foo is int 2 | foo() { return 1; } 3 | int bar = foo(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typeInference3.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | foo() { return ""; } 3 | // this assignment should fail 4 | int bar = foo(); -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typePredicate1.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | 3 | test() { 4 | mixed o; 5 | if (fn(o)) { 6 | // this should fail because o is a string 7 | int s = o; 8 | } else { 9 | 10 | } 11 | } 12 | 13 | /** 14 | * 15 | * @param o 16 | * @returns {o is string} 17 | */ 18 | fn(mixed o) { 19 | return 1; 20 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typePredicate2.c: -------------------------------------------------------------------------------- 1 | test() { 2 | mixed o; 3 | if (fn(o)) { 4 | int id = o->query_number(); 5 | } 6 | } 7 | 8 | /** 9 | * 10 | * @param o 11 | * @returns {o is "object.c"} 12 | */ 13 | fn(mixed o) { 14 | return 1; 15 | } 16 | 17 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/typePredicate3.c: -------------------------------------------------------------------------------- 1 | test() { 2 | object o; 3 | if (fn(o)) { 4 | int id = o->query_number(); 5 | } 6 | } 7 | 8 | /** 9 | * 10 | * @param o 11 | * @returns {o is "object.c"} 12 | */ 13 | fn(object o) { 14 | return 1; 15 | } 16 | 17 | // this tests for https://github.com/jlchmura/lpc-language-server/issues/238 18 | // @files: object.c -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/unionTypes.c: -------------------------------------------------------------------------------- 1 | // @driver: ldmud 2 | // unionable types 3 | public * testUnionable() { 4 | tmp = 0; 5 | return ({ 1, ({ "a" }) }); 6 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/varBeforeDecl.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | test() { 3 | i = 1; 4 | int i; 5 | } -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/varBeforeDecl2.c: -------------------------------------------------------------------------------- 1 | // @errors: 1 2 | i = 1; 3 | int i; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/varBeforeDecl3.c: -------------------------------------------------------------------------------- 1 | // this should not error 2 | test() { 3 | i = 1; 4 | } 5 | 6 | int i; -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/variadic1.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {mixed...} args 4 | */ 5 | test(args...) { 6 | return args; 7 | } 8 | 9 | // should support lpcdoc-style variadic params 10 | // @driver: fluffos 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/variadic2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {...mixed} args 4 | */ 5 | test(args...) { 6 | return args; 7 | } 8 | 9 | // also support jsdoc-style variadic, because why not? 10 | // @driver: fluffos 11 | -------------------------------------------------------------------------------- /server/src/tests/cases/compiler/while1.c: -------------------------------------------------------------------------------- 1 | // while loop 2 | testWhile() { 3 | int i=0; 4 | while(i<10) { 5 | write(i); 6 | i++; 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/tests/test-assets/basic.c: -------------------------------------------------------------------------------- 1 | #define FOO 1 2 | #define WR(x) write(x) 3 | 4 | int test() { 5 | WR(sprintf("%s", FOO)); 6 | return 1; 7 | } -------------------------------------------------------------------------------- /server/src/tests/test-assets/call-by-ref.fluffos.c: -------------------------------------------------------------------------------- 1 | 2 | void test(int i, string ref *keys, int j) { 3 | 4 | } 5 | 6 | void test2() { 7 | string *keys = ({ "a", "b" }); 8 | test(1, ref keys, 2); 9 | } -------------------------------------------------------------------------------- /server/src/tests/test-assets/fluffos-new.c: -------------------------------------------------------------------------------- 1 | class Foo { 2 | int a; 3 | string cool_var; 4 | } 5 | class Bar { 6 | string cool_var; 7 | } 8 | 9 | void main() { 10 | // parsing the fluffos _new class_ style syntax 11 | mixed m = new(class Bar, cool_var: "old data"); 12 | printf("Class cast test:\n"); 13 | printf("cool_var = %s\n", ((class Bar)m)->cool_var); 14 | evaluate((: ((class Bar)$1)->cool_var = $2 :), m, "new data"); 15 | printf("cool_var = %s\n", ((class Bar)m)->cool_var); 16 | } -------------------------------------------------------------------------------- /server/src/tests/test-assets/fluffos.h: -------------------------------------------------------------------------------- 1 | #define FLUFFOS_H 1 2 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/includes-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ldmud.h" 3 | #include "includes-test.h" 4 | 5 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/includes-test.h: -------------------------------------------------------------------------------- 1 | 2 | #define FOO "bar" 3 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/ldmud.h: -------------------------------------------------------------------------------- 1 | 2 | #define LDMUD_H 1 3 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/obj.c: -------------------------------------------------------------------------------- 1 | 2 | string query_name() { 3 | return "name"; 4 | } 5 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/parser-error.c: -------------------------------------------------------------------------------- 1 | 2 | test() { 3 | int i; 4 | int j; 5 | 6 | return 1; 7 | 8 | // this should report a parse error 9 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/preproc.c: -------------------------------------------------------------------------------- 1 | 2 | // directives can have a space after them 3 | 4 | test() { 5 | # ifdef MACRO_NOTDEFINED 6 | // this should be disabled 7 | int i=0; 8 | # endif 9 | 10 | // undef should be allowed inside methods 11 | #undef FOO 12 | 13 | } 14 | 15 | // and outside methods 16 | #undef BAR 17 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/syntax-functions.fluffos.c: -------------------------------------------------------------------------------- 1 | 2 | /* fluffos allows ineline closures as default param values */ 3 | void runit(int x: (: 10 :)) { 4 | printf("%d\n", x) ; 5 | } 6 | -------------------------------------------------------------------------------- /server/src/tests/test-assets/syntax-switch.fluffos.c: -------------------------------------------------------------------------------- 1 | 2 | /* fluffos allows open ended ranges in case statements */ 3 | void func() { 4 | int n ; 5 | 6 | switch(n) { 7 | case ..5: 8 | write("n is less than or equal to 5\n") ; 9 | break; 10 | case 6: 11 | write("n is 6\n") ; 12 | break; 13 | case 7.. : 14 | write("n is greater than or equal to 7\n") ; 15 | break; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /server/src/tests/test-utils.ts: -------------------------------------------------------------------------------- 1 | // import * as fs from "fs"; 2 | // import * as path from "path"; 3 | // import { 4 | // BailErrorStrategy, 5 | // CharStream, 6 | // CommonTokenStream, 7 | // PredictionMode, 8 | // } from "antlr4ng"; 9 | // import { LPCPreprocessingLexer } from "../parser3/LPCPreprocessingLexer"; 10 | // import { LPCTokenFactor } from "../parser3/LPCTokenFactory"; 11 | // import { TestFileHandler } from "./TestFileHandler"; 12 | // import { IDiagnosticEntry } from "../types"; 13 | // import { LPCParser } from "../parser3/LPCParser"; 14 | // import { DriverType } from "../config-types"; 15 | // import { LPCLexer } from "../parser3/LPCLexer"; 16 | 17 | // const baseDir = path.join(process.cwd(), "server/src/tests/test-assets/"); 18 | 19 | // export function resolveTestFilePath(filename: string): string { 20 | // return path.join(baseDir, filename); 21 | // } 22 | 23 | // function getStream(filename: string): CharStream { 24 | // const f = path.join( 25 | // process.cwd(), 26 | // "server/src/tests/test-assets/", 27 | // filename 28 | // ); 29 | // return CharStream.fromString(fs.readFileSync(f, "utf8").toString()); 30 | // } 31 | 32 | // export function getLexer( 33 | // filename: string, 34 | // diags: IDiagnosticEntry[] = [] 35 | // ): LPCPreprocessingLexer { 36 | // const stream = getStream(filename); 37 | // const lexer = new LPCPreprocessingLexer(stream, filename); 38 | // lexer.tokenFactory = new LPCTokenFactor(filename); 39 | // lexer.fileHandler = new TestFileHandler(); 40 | // return lexer; 41 | // } 42 | 43 | // export function getLexerFromString( 44 | // s: string, 45 | // diags: IDiagnosticEntry[] = [] 46 | // ): LPCPreprocessingLexer { 47 | // const stream = CharStream.fromString(s); 48 | // const lexer = new LPCPreprocessingLexer(stream, "test.c"); 49 | // lexer.tokenFactory = new LPCTokenFactor("test.c"); 50 | // lexer.fileHandler = new TestFileHandler(); 51 | // return lexer; 52 | // } 53 | 54 | // function getParserImpl(lexer: LPCLexer, driverType: DriverType) { 55 | // lexer.driverType = driverType; 56 | 57 | // const tokenStream = new CommonTokenStream(lexer); 58 | // tokenStream.fill(); 59 | 60 | // const parser = new LPCParser(tokenStream); 61 | // parser.interpreter.predictionMode = PredictionMode.SLL; 62 | // parser.driverType = lexer.driverType; 63 | // parser.setTokenFactory(lexer.tokenFactory); 64 | // parser.buildParseTrees = true; 65 | // parser.errorHandler = new BailErrorStrategy(); 66 | // return parser; 67 | // } 68 | 69 | // export function getParserFromString(code: string, driverType: DriverType) { 70 | // const lexer = getLexerFromString(code); 71 | // return getParserImpl(lexer, driverType); 72 | // } 73 | 74 | // export function getParser(filename: string, driverType: DriverType) { 75 | // return getParserImpl(getLexer(filename), driverType); 76 | // } 77 | -------------------------------------------------------------------------------- /server/src/types.ts: -------------------------------------------------------------------------------- 1 | export const SemanticTokenTypes = { 2 | Comment: 0, 3 | Macro: 1, 4 | Operator: 2, 5 | Method: 3, 6 | Parameter: 4, 7 | Define: 5, 8 | String: 6, 9 | Number: 7, 10 | Type: 8, 11 | Variable: 9, 12 | Property: 10, 13 | LambdaPrefix: 11, 14 | } as const; 15 | 16 | export const SemanticTokenModifiers = { 17 | Declaration: 1, 18 | Definition: 2, 19 | Documentation: 3, 20 | Static: 4, 21 | DefaultLibrary: 5, 22 | Local: 6, 23 | } as const; 24 | -------------------------------------------------------------------------------- /server/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { URI } from "vscode-uri"; 2 | 3 | /** 4 | * Add a file extension to a filename if it doesn't have one 5 | * @param filename filename to normalize 6 | * @returns 7 | */ 8 | export function normalizeFileExtension(filename: string) { 9 | if (!filename) return filename; 10 | 11 | if (!filename.endsWith(".c") && !filename.endsWith(".h")) { 12 | filename += ".c"; 13 | } 14 | 15 | return filename; 16 | } 17 | 18 | export function normalizeFilename(filename: string) { 19 | if (!filename) return filename; 20 | 21 | filename = normalizeFileExtension(filename); 22 | 23 | if (filename.startsWith("file:")) { 24 | const uri = URI.parse(filename); 25 | const fsPath = uri.fsPath; 26 | return fsPath; 27 | } else { 28 | return filename; 29 | } 30 | } 31 | 32 | 33 | export function trimStart(original: string, toRemove: string): string { 34 | if (original?.startsWith(toRemove)) { 35 | return original.slice(toRemove.length); 36 | } 37 | return original; 38 | } 39 | 40 | export function pushIfDefined(arr: T[], item: T) { 41 | if (!!item) { 42 | arr.push(item); 43 | } 44 | } 45 | 46 | /** 47 | * tests if a filename is surrounded by chars @c and if so 48 | * removes them 49 | * @param filename 50 | * @param c 51 | * @returns 52 | */ 53 | export function testFilename( 54 | filename: string, 55 | c: string, 56 | cEnd: string 57 | ): string { 58 | if (filename.startsWith(c) && filename.endsWith(cEnd)) { 59 | return filename.slice(1, filename.length - 1); 60 | } else { 61 | return filename; 62 | } 63 | } 64 | 65 | /** escape a string for use in regex */ 66 | export function escapeRegExp(str: string) { 67 | return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 68 | } 69 | 70 | export function areWeTestingWithJest() { 71 | return process.env.JEST_WORKER_ID !== undefined; 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "outDir": "../out/local", 5 | "pretty": true, 6 | "sourceRoot": "./src", 7 | "rootDirs": ["src"], 8 | "baseUrl": "./", 9 | 10 | "lib": ["es2020"], 11 | "target": "es2020", 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | 15 | "declaration": false, 16 | "sourceMap": true, 17 | "composite": false, 18 | "stripInternal": true, 19 | 20 | "skipLibCheck": true, 21 | 22 | "esModuleInterop": true, 23 | "resolveJsonModule": true, 24 | "strict": false, 25 | "newLine": "lf", 26 | "preserveConstEnums": true, 27 | 28 | "noImplicitOverride": false, 29 | }, 30 | "include": ["src"], 31 | "exclude": ["node_modules", ".vscode-test", "tests"] 32 | } 33 | -------------------------------------------------------------------------------- /server/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["**/tests/**/*"], 4 | "compilerOptions": { 5 | "outDir": "../out/local-dts", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "emitDeclarationOnly": true 9 | } 10 | } -------------------------------------------------------------------------------- /syntaxes/lpcdoc.injection.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "injectionSelector": "L:comment.block.documentation", 3 | "patterns": [ 4 | { 5 | "include": "#lpcdocbody" 6 | } 7 | ], 8 | "repository": { 9 | "fenced_code_block_lpc": { 10 | "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lpc)?((\\s+|:|,|\\{|\\?)[^`]*)?$)", 11 | "name": "markup.fenced_code.block.markdown", 12 | "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", 13 | "beginCaptures": { 14 | "3": { 15 | "name": "punctuation.definition.markdown" 16 | }, 17 | "4": { 18 | "name": "fenced_code.block.language.markdown" 19 | }, 20 | "5": { 21 | "name": "fenced_code.block.language.attributes.markdown" 22 | } 23 | }, 24 | "endCaptures": { 25 | "3": { 26 | "name": "punctuation.definition.markdown" 27 | } 28 | }, 29 | "patterns": [ 30 | { 31 | "begin": "(^|\\G)(\\s*)(.*)", 32 | "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", 33 | "contentName": "meta.embedded.block.lpc", 34 | "patterns": [ 35 | { 36 | "include": "source.lpc.lang-server" 37 | } 38 | ] 39 | } 40 | ] 41 | }, 42 | "lpcdocbody": { 43 | "begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$", 44 | "while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)", 45 | "patterns": [ 46 | { 47 | "include": "#fenced_code_block_lpc" 48 | }, 49 | { 50 | "include": "text.html.markdown#fenced_code_block" 51 | }, 52 | { 53 | "include": "#example" 54 | }, 55 | { 56 | "include": "source.lpc.lang-server#docblock" 57 | }, 58 | { 59 | "include": "text.html.markdown#inline" 60 | } 61 | ] 62 | }, 63 | "example": { 64 | "begin": "((@)example)\\s+(?=([^*]|[*](?!/))*$).*$", 65 | "while": "(^|\\G)\\s(?!@)(?=([^*]|[*](?!/))*$)", 66 | "beginCaptures": { 67 | "1": { 68 | "name": "storage.type.class.lpcdoc" 69 | }, 70 | "2": { 71 | "name": "punctuation.definition.block.tag.lpcdoc" 72 | } 73 | }, 74 | "contentName": "meta.embedded.block.example.source.lpc", 75 | "patterns": [ 76 | { 77 | "include": "source.lpc.lang-server" 78 | } 79 | ] 80 | } 81 | }, 82 | "scopeName": "documentation.injection.lpc" 83 | } 84 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "outDir": "./out/local", 5 | "pretty": true, 6 | 7 | "lib": ["es2020"], 8 | "target": "es2020", 9 | "module": "ESNext", 10 | "moduleResolution": "Node", 11 | 12 | "declaration": true, 13 | "declarationMap": true, 14 | "sourceMap": true, 15 | "composite": false, 16 | "emitDeclarationOnly": true, 17 | 18 | "skipLibCheck": true, 19 | 20 | "esModuleInterop": true, 21 | "resolveJsonModule": true, 22 | "strict": false, 23 | "newLine": "lf", 24 | "preserveConstEnums": true, 25 | 26 | "noImplicitOverride": false, 27 | }, 28 | "include": ["src"], 29 | "exclude": ["node_modules", ".vscode-test"], 30 | "references": [{ "path": "./client" }, { "path": "./server" }] 31 | } 32 | --------------------------------------------------------------------------------