├── .gitattributes
├── .github
└── workflows
│ ├── docs.yml
│ └── gradle.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── build.gradle
├── dist
├── icon.png
├── own
├── own.cmd
├── ownlang
├── ownlang-runner.cmd
└── ownlang.cmd
├── docs
├── .gitignore
├── build.gradle
├── docs
│ ├── .vuepress
│ │ ├── components
│ │ │ ├── Scope.vue
│ │ │ └── Since.vue
│ │ ├── config.js
│ │ ├── configs
│ │ │ ├── navbar.js
│ │ │ ├── pages.js
│ │ │ └── sidebar.js
│ │ └── styles
│ │ │ └── palette.scss
│ ├── README.md
│ ├── code
│ │ ├── basics
│ │ │ ├── destructuring_assignment1.own
│ │ │ ├── destructuring_assignment2.own
│ │ │ ├── destructuring_assignment3.own
│ │ │ ├── destructuring_assignment4.own
│ │ │ ├── fibonacci.own
│ │ │ ├── loops1.own
│ │ │ ├── pattern_matching1.own
│ │ │ ├── pattern_matching2.own
│ │ │ ├── pattern_matching3.own
│ │ │ ├── pattern_matching4.own
│ │ │ ├── pattern_matching5.own
│ │ │ ├── pattern_matching6.own
│ │ │ └── string_functions1.own
│ │ ├── functional_en.own
│ │ ├── functional_ru.own
│ │ ├── high_order_functions_en.own
│ │ ├── high_order_functions_ru.own
│ │ ├── http_en.own
│ │ ├── http_ru.own
│ │ ├── operator_overloading.own
│ │ └── pattern_matching.own
│ ├── en
│ │ ├── README.md
│ │ ├── basics
│ │ │ ├── README.md
│ │ │ ├── array_functions.md
│ │ │ ├── comments.md
│ │ │ ├── destructuring_assignment.md
│ │ │ ├── functions.md
│ │ │ ├── loops.md
│ │ │ ├── pattern_matching.md
│ │ │ ├── string_functions.md
│ │ │ ├── strings.md
│ │ │ └── types.md
│ │ ├── changelog.md
│ │ └── links.md
│ └── ru
│ │ ├── README.md
│ │ ├── basics
│ │ ├── README.md
│ │ ├── array_functions.md
│ │ ├── comments.md
│ │ ├── destructuring_assignment.md
│ │ ├── functions.md
│ │ ├── loops.md
│ │ ├── pattern_matching.md
│ │ ├── string_functions.md
│ │ ├── strings.md
│ │ └── types.md
│ │ ├── changelog.md
│ │ └── links.md
├── package.json
├── pnpm-lock.yaml
└── src
│ ├── docgen-md.own
│ ├── main
│ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ └── docs
│ │ ├── ModuleInfo.java
│ │ └── ModulesInfoCreator.java
│ └── modules
│ ├── android.yml
│ ├── base64.yml
│ ├── canvas.yml
│ ├── canvas_android.yml
│ ├── canvasfx.yml
│ ├── collections.yml
│ ├── date.yml
│ ├── downloader.yml
│ ├── files.yml
│ ├── forms.yml
│ ├── forms_android.yml
│ ├── functional.yml
│ ├── gps_android.yml
│ ├── gzip.yml
│ ├── http.yml
│ ├── imageprocessing_android.yml
│ ├── java.yml
│ ├── jdbc.yml
│ ├── json.yml
│ ├── math.yml
│ ├── okhttp.yml
│ ├── ounit.yml
│ ├── regex.yml
│ ├── robot.yml
│ ├── server.yml
│ ├── socket.yml
│ ├── std.yml
│ ├── types.yml
│ ├── yaml.yml
│ └── zip.yml
├── editors
├── README.md
├── gtksourceview
│ └── ownlang.lang
├── highlighjs
│ └── own.js
├── idea
│ ├── IntelliJ IDEA Global Settings
│ └── filetypes
│ │ └── OwnLang.xml
└── prismjs
│ └── own-language.js
├── examples
├── basics
│ ├── array.own
│ ├── bitwise_operators.own
│ ├── classes.own
│ ├── destructuring_assignment.own
│ ├── extended_identifier.own
│ ├── loops.own
│ ├── map.own
│ ├── operator_overloading.own
│ ├── pattern_matching.own
│ ├── ternary_operator.own
│ ├── thread.own
│ └── types.own
├── canvas
│ ├── 1.own
│ ├── 2.own
│ ├── animate_line.own
│ ├── animate_line_thread.own
│ ├── control_point.own
│ ├── fractal_polygon.own
│ ├── fractal_rect.own
│ ├── fx_basic_shapes.own
│ ├── fx_event_handlers.own
│ ├── fx_global_alpha.own
│ ├── fx_image.own
│ ├── fx_image_negate.own
│ ├── fx_koch_snowflake.own
│ └── fx_rotation.own
├── console
│ └── colors.own
├── database
│ ├── hsqldb.own
│ └── sqlite.own
├── formats
│ ├── gzip.own
│ ├── json.own
│ ├── yaml.own
│ └── zip.own
├── forms
│ ├── basic.own
│ ├── button.own
│ ├── chatgpt.own
│ ├── complicatedForm.own
│ ├── look_and_feel.own
│ ├── panel.own
│ ├── progressbar.own
│ ├── samobot_chat.own
│ ├── textarea.own
│ ├── textfield.own
│ └── windowlistener.own
├── functions
│ ├── basics.own
│ ├── calculator.own
│ ├── chain.own
│ ├── default_arguments.own
│ ├── factorial.own
│ ├── filter_map.own
│ ├── flatmap.own
│ ├── function_call_chain.own
│ ├── function_chain.own
│ ├── groupby.own
│ ├── reduce.own
│ ├── sortby.own
│ ├── stream.own
│ └── tomap.own
├── game
│ ├── agar.own
│ ├── minesweeper.own
│ ├── pipes-online
│ │ ├── pipes_online.own
│ │ └── server
│ │ │ ├── main.js
│ │ │ └── package.json
│ ├── pipes.own
│ └── pipes_online.own
├── java
│ ├── collections.own
│ └── system_info.own
├── network
│ ├── demo.own
│ ├── github_timeline.own
│ ├── okhttp_imgur_upload.own
│ ├── okhttp_telegram_sendvoice.own
│ ├── okhttp_websocket.own
│ ├── telegram_api.own
│ └── twitch_tools.own
├── robot
│ └── paint_lines.own
├── server
│ ├── notes_public
│ │ ├── index.html
│ │ ├── notes.js
│ │ └── styles.css
│ ├── server_spa.own
│ └── server_spa_simple.own
└── versions
│ ├── whatsnew_1.5.0.own
│ └── whatsnew_2.0.0.own
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── modules
├── canvasfx
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ └── modules
│ │ └── canvasfx
│ │ └── canvasfx.java
├── jdbc
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ └── modules
│ │ └── jdbc
│ │ ├── ConnectionValue.java
│ │ ├── JdbcConverters.java
│ │ ├── ResultSetValue.java
│ │ ├── StatementValue.java
│ │ └── jdbc.java
├── main
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ └── modules
│ │ ├── base64
│ │ └── base64.java
│ │ ├── canvas
│ │ └── canvas.java
│ │ ├── collections
│ │ └── collections.java
│ │ ├── date
│ │ └── date.java
│ │ ├── downloader
│ │ └── downloader.java
│ │ ├── files
│ │ └── files.java
│ │ ├── forms
│ │ ├── AbstractButtonValue.java
│ │ ├── ComponentValue.java
│ │ ├── Components.java
│ │ ├── ContainerValue.java
│ │ ├── JButtonValue.java
│ │ ├── JComponentValue.java
│ │ ├── JFrameValue.java
│ │ ├── JLabelValue.java
│ │ ├── JPanelValue.java
│ │ ├── JProgressBarValue.java
│ │ ├── JScrollPaneValue.java
│ │ ├── JTextAreaValue.java
│ │ ├── JTextComponentValue.java
│ │ ├── JTextFieldValue.java
│ │ ├── LayoutManagerValue.java
│ │ ├── LayoutManagers.java
│ │ ├── WindowValue.java
│ │ └── forms.java
│ │ ├── functional
│ │ ├── StreamValue.java
│ │ ├── functional.java
│ │ ├── functional_chain.java
│ │ ├── functional_combine.java
│ │ ├── functional_dropWhile.java
│ │ ├── functional_filter.java
│ │ ├── functional_filterNot.java
│ │ ├── functional_flatmap.java
│ │ ├── functional_forEach.java
│ │ ├── functional_forEachIndexed.java
│ │ ├── functional_groupBy.java
│ │ ├── functional_map.java
│ │ ├── functional_match.java
│ │ ├── functional_reduce.java
│ │ ├── functional_sortBy.java
│ │ ├── functional_stream.java
│ │ ├── functional_takeWhile.java
│ │ └── functional_toMap.java
│ │ ├── gzip
│ │ └── gzip.java
│ │ ├── http
│ │ ├── HttpFunctions.java
│ │ ├── http.java
│ │ ├── http_download.java
│ │ └── http_urlencode.java
│ │ ├── java
│ │ └── java.java
│ │ ├── json
│ │ ├── json.java
│ │ ├── json_decode.java
│ │ └── json_encode.java
│ │ ├── math
│ │ └── math.java
│ │ ├── okhttp
│ │ ├── CallValue.java
│ │ ├── HttpClientBuilderValue.java
│ │ ├── HttpClientValue.java
│ │ ├── MultipartBodyBuilderValue.java
│ │ ├── MultipartBodyValue.java
│ │ ├── RequestBodyValue.java
│ │ ├── RequestBuilderValue.java
│ │ ├── ResponseBodyValue.java
│ │ ├── ResponseValue.java
│ │ ├── Values.java
│ │ ├── WebSocketValue.java
│ │ └── okhttp.java
│ │ ├── ounit
│ │ └── ounit.java
│ │ ├── regex
│ │ ├── MatcherValue.java
│ │ ├── PatternValue.java
│ │ └── regex.java
│ │ ├── robot
│ │ ├── robot.java
│ │ ├── robot_exec.java
│ │ ├── robot_fromclipboard.java
│ │ └── robot_toclipboard.java
│ │ ├── std
│ │ ├── ArrayFunctions.java
│ │ ├── NumberFunctions.java
│ │ ├── StringFunctions.java
│ │ ├── SystemFunctions.java
│ │ ├── std.java
│ │ ├── std_arrayCombine.java
│ │ ├── std_arrayKeyExists.java
│ │ ├── std_arrayKeys.java
│ │ ├── std_arraySplice.java
│ │ ├── std_arrayValues.java
│ │ ├── std_charat.java
│ │ ├── std_default.java
│ │ ├── std_echo.java
│ │ ├── std_indexof.java
│ │ ├── std_join.java
│ │ ├── std_lastindexof.java
│ │ ├── std_length.java
│ │ ├── std_newarray.java
│ │ ├── std_rand.java
│ │ ├── std_range.java
│ │ ├── std_readln.java
│ │ ├── std_replace.java
│ │ ├── std_replaceall.java
│ │ ├── std_replacefirst.java
│ │ ├── std_sleep.java
│ │ ├── std_sort.java
│ │ ├── std_split.java
│ │ ├── std_sprintf.java
│ │ ├── std_substring.java
│ │ ├── std_sync.java
│ │ ├── std_thread.java
│ │ ├── std_tochar.java
│ │ ├── std_tolowercase.java
│ │ ├── std_touppercase.java
│ │ ├── std_trim.java
│ │ └── std_try.java
│ │ ├── types
│ │ └── types.java
│ │ ├── yaml
│ │ ├── yaml.java
│ │ ├── yaml_decode.java
│ │ └── yaml_encode.java
│ │ └── zip
│ │ └── zip.java
├── server
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ └── modules
│ │ └── server
│ │ ├── Config.java
│ │ ├── ContextValue.java
│ │ ├── ServerValue.java
│ │ └── server.java
└── socket
│ ├── build.gradle
│ └── src
│ └── main
│ └── java
│ └── com
│ └── annimon
│ └── ownlang
│ └── modules
│ └── socket
│ └── socket.java
├── ownlang-core
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── annimon
│ └── ownlang
│ ├── Console.java
│ ├── Shared.java
│ ├── Version.java
│ ├── exceptions
│ ├── ArgumentsMismatchException.java
│ ├── OperationIsNotSupportedException.java
│ ├── OwnLangRuntimeException.java
│ ├── PatternMatchingException.java
│ ├── StoppedException.java
│ ├── TypeException.java
│ ├── UnknownClassException.java
│ ├── UnknownFunctionException.java
│ ├── UnknownPropertyException.java
│ └── VariableDoesNotExistsException.java
│ ├── lib
│ ├── Arguments.java
│ ├── ArrayValue.java
│ ├── AutoCloseableScope.java
│ ├── CallStack.java
│ ├── ClassDeclaration.java
│ ├── ClassField.java
│ ├── ClassInstance.java
│ ├── ClassMethod.java
│ ├── Converters.java
│ ├── EvaluableValue.java
│ ├── Function.java
│ ├── FunctionValue.java
│ ├── Functions.java
│ ├── Instantiable.java
│ ├── MapValue.java
│ ├── ModuleLoader.java
│ ├── NumberValue.java
│ ├── RootScope.java
│ ├── Scope.java
│ ├── ScopeHandler.java
│ ├── StringValue.java
│ ├── Types.java
│ ├── Value.java
│ ├── ValueUtils.java
│ └── Variables.java
│ ├── modules
│ └── Module.java
│ ├── outputsettings
│ ├── ConsoleOutputSettings.java
│ ├── OutputSettings.java
│ └── StringOutputSettings.java
│ ├── stages
│ ├── ScopedStage.java
│ ├── ScopedStageFactory.java
│ ├── Stage.java
│ ├── StagesData.java
│ └── StagesDataMap.java
│ └── util
│ ├── ErrorsLocationFormatterStage.java
│ ├── ErrorsStackTraceFormatterStage.java
│ ├── ExceptionConverterStage.java
│ ├── ExceptionStackTraceToStringStage.java
│ ├── Pos.java
│ ├── Range.java
│ ├── SimpleError.java
│ ├── SourceLocatedError.java
│ ├── SourceLocation.java
│ ├── SourceLocationFormatterStage.java
│ └── input
│ ├── InputSource.java
│ ├── InputSourceDetector.java
│ ├── InputSourceFile.java
│ ├── InputSourceProgram.java
│ ├── InputSourceResource.java
│ └── SourceLoaderStage.java
├── ownlang-desktop
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ ├── Main.java
│ │ └── RunOptions.java
│ └── resources
│ └── scripts
│ ├── checkupdate.own
│ ├── listscripts.own
│ ├── own.own
│ └── own
│ ├── Config.own
│ ├── Own.own
│ ├── Packages.own
│ ├── Projects.own
│ └── Registry.own
├── ownlang-parser
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── annimon
│ │ └── ownlang
│ │ ├── exceptions
│ │ ├── OwnLangParserException.java
│ │ └── ParseException.java
│ │ ├── lib
│ │ └── UserDefinedFunction.java
│ │ ├── parser
│ │ ├── BeautifierStage.java
│ │ ├── Lexer.java
│ │ ├── Parser.java
│ │ ├── ParserMetadata.java
│ │ ├── SourceLoader.java
│ │ ├── Token.java
│ │ ├── TokenType.java
│ │ ├── ast
│ │ │ ├── Accessible.java
│ │ │ ├── Argument.java
│ │ │ ├── Arguments.java
│ │ │ ├── ArrayExpression.java
│ │ │ ├── AssignmentExpression.java
│ │ │ ├── BinaryExpression.java
│ │ │ ├── BlockStatement.java
│ │ │ ├── BreakStatement.java
│ │ │ ├── ClassDeclarationStatement.java
│ │ │ ├── ConditionalExpression.java
│ │ │ ├── ContainerAccessExpression.java
│ │ │ ├── ContinueStatement.java
│ │ │ ├── DestructuringAssignmentStatement.java
│ │ │ ├── DoWhileStatement.java
│ │ │ ├── ExprStatement.java
│ │ │ ├── ForStatement.java
│ │ │ ├── ForeachArrayStatement.java
│ │ │ ├── ForeachMapStatement.java
│ │ │ ├── FunctionDefineStatement.java
│ │ │ ├── FunctionReferenceExpression.java
│ │ │ ├── FunctionalExpression.java
│ │ │ ├── IfStatement.java
│ │ │ ├── IncludeStatement.java
│ │ │ ├── InterruptableNode.java
│ │ │ ├── MapExpression.java
│ │ │ ├── MatchExpression.java
│ │ │ ├── Node.java
│ │ │ ├── ObjectCreationExpression.java
│ │ │ ├── PrintStatement.java
│ │ │ ├── PrintlnStatement.java
│ │ │ ├── ResultVisitor.java
│ │ │ ├── ReturnStatement.java
│ │ │ ├── Statement.java
│ │ │ ├── TernaryExpression.java
│ │ │ ├── UnaryExpression.java
│ │ │ ├── UseStatement.java
│ │ │ ├── ValueExpression.java
│ │ │ ├── VariableExpression.java
│ │ │ ├── Visitor.java
│ │ │ └── WhileStatement.java
│ │ ├── error
│ │ │ ├── ParseError.java
│ │ │ ├── ParseErrors.java
│ │ │ └── ParseErrorsFormatterStage.java
│ │ ├── linters
│ │ │ ├── AssignValidator.java
│ │ │ ├── DefaultFunctionsOverrideValidator.java
│ │ │ ├── IncludeSourceValidator.java
│ │ │ ├── LintVisitor.java
│ │ │ ├── LinterResult.java
│ │ │ ├── LinterResults.java
│ │ │ ├── LinterStage.java
│ │ │ └── LoopStatementsValidator.java
│ │ ├── optimization
│ │ │ ├── ConstantFolding.java
│ │ │ ├── ConstantPropagation.java
│ │ │ ├── DeadCodeElimination.java
│ │ │ ├── ExpressionSimplification.java
│ │ │ ├── InstructionCombining.java
│ │ │ ├── Optimizable.java
│ │ │ ├── OptimizationStage.java
│ │ │ ├── OptimizationVisitor.java
│ │ │ ├── SummaryOptimization.java
│ │ │ ├── VariableInfo.java
│ │ │ └── VariablesGrabber.java
│ │ └── visitors
│ │ │ ├── AbstractVisitor.java
│ │ │ ├── FunctionAdder.java
│ │ │ ├── ModuleDetector.java
│ │ │ ├── PrintVisitor.java
│ │ │ ├── VariablePrinter.java
│ │ │ └── VisitorUtils.java
│ │ └── stages
│ │ ├── ExecutionStage.java
│ │ ├── FunctionAddingStage.java
│ │ ├── LexerStage.java
│ │ └── ParserStage.java
│ └── test
│ ├── java
│ ├── com
│ │ └── annimon
│ │ │ └── ownlang
│ │ │ └── parser
│ │ │ ├── LexerBenchmarkTest.java
│ │ │ ├── LexerPositionsTest.java
│ │ │ ├── LexerTest.java
│ │ │ ├── LexerValidDataProvider.java
│ │ │ ├── MockOUnitStage.java
│ │ │ ├── ParserBenchmarkTest.java
│ │ │ ├── ParserTest.java
│ │ │ ├── ProgramsBenchmarkTest.java
│ │ │ ├── ProgramsTest.java
│ │ │ ├── TestDataUtil.java
│ │ │ └── ast
│ │ │ ├── ASTHelper.java
│ │ │ ├── OperatorExpressionTest.java
│ │ │ ├── ValueExpressionTest.java
│ │ │ └── VariableExpressionTest.java
│ └── interop
│ │ └── Data.java
│ └── resources
│ ├── benchmarks
│ ├── calculator.own
│ └── useStatement.own
│ ├── expressions
│ ├── assignmentExpression.own
│ ├── binaryExpressionOnNumbers.own
│ ├── binaryExpressionOnStrings.own
│ ├── binaryUnaryExpr.own
│ ├── foreachKeyValue.own
│ ├── foreachValue.own
│ ├── functionReference.own
│ ├── include.own
│ ├── includeClass.own.txt
│ ├── includeParseErrorSource.own.txt
│ ├── matchExpression.own
│ ├── nullCoalesce.own
│ ├── unaryExpressionOnStrings.own
│ └── varFuncSameName.own
│ ├── modules
│ ├── base64
│ │ └── base64.own
│ ├── date
│ │ ├── compareDates.own
│ │ ├── dateFormat.own
│ │ ├── dateParse.own
│ │ └── newDate.own
│ ├── files
│ │ └── files.own
│ ├── functional
│ │ ├── chain.own
│ │ ├── foreach.own
│ │ ├── groupby.own
│ │ ├── stream.own
│ │ └── tomap.own
│ ├── gzip
│ │ └── gzipBytes.own
│ ├── java
│ │ └── classes.own
│ ├── regex
│ │ ├── match.own
│ │ └── replaceCallback.own
│ ├── std
│ │ ├── arraySplice.own
│ │ ├── default.own
│ │ ├── getBytes.own
│ │ ├── indexOf.own
│ │ ├── lastIndexOf.own
│ │ ├── parseInt.own
│ │ ├── parseLong.own
│ │ ├── range.own
│ │ ├── stringFromBytes.own
│ │ ├── stripMargin.own
│ │ ├── toHexString.own
│ │ └── try.own
│ └── yaml
│ │ ├── yamldecode.own
│ │ └── yamlencode.own
│ └── other
│ ├── arrayFunctions.own
│ ├── classScope.own
│ ├── functionChain.own
│ ├── recursion.own
│ ├── scope.own
│ ├── stringFunctions.own
│ ├── types.own
│ └── useStatementScope.own
├── ownlang-utils
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── annimon
│ └── ownlang
│ └── utils
│ ├── OptimizationDumper.java
│ ├── Repl.java
│ ├── Sandbox.java
│ ├── TimeMeasurement.java
│ └── repl
│ ├── JLineConsole.java
│ ├── OwnLangCompleter.java
│ ├── ReplConsole.java
│ └── SystemConsole.java
├── program.own
├── proguard.properties
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.own linguist-language=Scala
2 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches: [ "latest" ]
6 | pull_request:
7 | branches: [ "latest" ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | java: [ '17', '21' ]
15 | name: Test
16 | steps:
17 | - uses: actions/checkout@v4
18 | - name: Set up JDK ${{ matrix.java }}
19 | uses: actions/setup-java@v4
20 | with:
21 | java-version: ${{ matrix.java }}
22 | distribution: 'temurin'
23 | - name: Setup Gradle
24 | uses: gradle/actions/setup-gradle@v4
25 | - name: Run tests
26 | run: ./gradlew test
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle/
2 | /.idea/
3 | /.nb-gradle/
4 | **/build/
5 | /out/
6 | /store/
7 | /optimizations/
8 | OwnLang.iml
9 | *.sh
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM gradle:8.13.0-jdk21-alpine AS cache
2 | RUN mkdir -p /home/gradle/cache_home
3 | ENV GRADLE_USER_HOME=/home/gradle/cache_home
4 | COPY build.gradle /home/gradle/java-code/
5 | WORKDIR /home/gradle/java-code
6 | RUN GRADLE_OPTS="-Xmx256m" gradle build --build-cache --stacktrace -i --no-daemon
7 |
8 | FROM gradle:8.13.0-jdk21-alpine AS builder
9 | COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle
10 | COPY . /usr/src/java-code
11 | WORKDIR /usr/src/java-code
12 | RUN GRADLE_OPTS="-Xmx256m" gradle shadowJar --build-cache --stacktrace --no-daemon
13 |
14 | FROM eclipse-temurin:21-jre-alpine
15 | WORKDIR /opt/ownlang
16 | ENV PATH /opt/ownlang:$PATH
17 | COPY --from=builder /usr/src/java-code/ownlang-desktop/build/libs/*.jar libs/OwnLang.jar
18 | COPY --from=builder /usr/src/java-code/modules/jdbc/build/libs/*.jar modules/
19 | COPY --from=builder /usr/src/java-code/modules/server/build/libs/*.jar modules/
20 | COPY --from=builder /usr/src/java-code/modules/socket/build/libs/*.jar modules/
21 | COPY dist/own .
22 | COPY dist/ownlang .
23 | RUN chmod +x own ownlang
24 | ENTRYPOINT ["ownlang"]
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2015-2016 Victor Melnik
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | versions = [
3 | project: '2.1.0',
4 |
5 | json: '20240303', // org.json:json
6 | snakeyaml: '1.33', // org.yaml:snakeyaml
7 | okhttp: '4.12.0', // com.squareup.okhttp3:okhttp
8 | socket: '2.1.1', // io.socket:socket.io-client
9 | jline: '2.14.6', // jline:jline
10 |
11 | javalin: '6.3.0', // io.javalin:javalin
12 | slf4j: '2.0.16', // org.slf4j:slf4j-simple
13 | jackson: '2.18.0', // com.fasterxml.jackson.core:jackson-databind
14 |
15 | junit: '5.11.2', // org.junit:junit-bom
16 | jmh: '1.37', // org.openjdk.jmh:jmh-core
17 | assertj: '3.26.3' // org.assertj:assertj-core
18 | ]
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | mavenCentral()
24 | }
25 |
26 | gradle.projectsEvaluated {
27 | tasks.withType(JavaCompile).tap {
28 | configureEach {
29 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
30 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/dist/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aNNiMON/Own-Programming-Language-Tutorial/f9c2bff15962b60ddc2d5b94a7f35d18e9b06900/dist/icon.png
--------------------------------------------------------------------------------
/dist/own:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | ownlang run own "$@"
--------------------------------------------------------------------------------
/dist/own.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | ownlang run own %*
--------------------------------------------------------------------------------
/dist/ownlang:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | (set -o igncr) 2>/dev/null && set -o igncr; # cygwin encoding fix
3 |
4 | # resolve links - $0 may be a softlink
5 | PRG="$0"
6 | while [ -h "$PRG" ] ; do
7 | ls=`ls -ld "$PRG"`
8 | link=`expr "$ls" : '.*-> \(.*\)$'`
9 | if expr "$link" : '/.*' > /dev/null; then
10 | PRG="$link"
11 | else
12 | PRG=`dirname "$PRG"`/"$link"
13 | fi
14 | done
15 | PRGDIR=`dirname "$PRG"`
16 |
17 | _classpath=".:$PRGDIR/OwnLang.jar"
18 | if [ `uname -a | grep -i -c cygwin` -ne 0 ]; then # Cygwin, translate the path
19 | for k in "$PRGDIR"/modules/*.jar
20 | do
21 | _classpath="${_classpath};`cygpath -w ${k}`"
22 | done
23 | for k in "$PRGDIR"/libs/*.jar
24 | do
25 | _classpath="${_classpath};`cygpath -w ${k}`"
26 | done
27 | else
28 | for k in "$PRGDIR"/modules/*.jar
29 | do
30 | _classpath="${_classpath}:${k}"
31 | done
32 | for k in "$PRGDIR"/libs/*.jar
33 | do
34 | _classpath="${_classpath}:${k}"
35 | done
36 | fi
37 |
38 | java -cp "${_classpath}" com.annimon.ownlang.Main "$@"
--------------------------------------------------------------------------------
/dist/ownlang-runner.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | set JAVA=java
3 | %JAVA% -cp "%~dp0/*;%~dp0modules/*;%~dp0libs/*" com.annimon.ownlang.Main --file %1
4 | pause
--------------------------------------------------------------------------------
/dist/ownlang.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | set JAVA=java
4 | %JAVA% ^
5 | -cp "%~dp0/*;%~dp0modules/*;%~dp0libs/*" com.annimon.ownlang.Main %*
6 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .temp
3 | .cache
4 | docs/.vuepress/configs/modules.js
5 | docs/.vuepress/dist/
6 | docs/*/modules/
7 |
--------------------------------------------------------------------------------
/docs/docs/.vuepress/components/Scope.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 | {{ scope }}
7 |
8 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/docs/.vuepress/components/Since.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ text }} {{ version }}
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/docs/.vuepress/configs/navbar.js:
--------------------------------------------------------------------------------
1 | import pages from './pages'
2 |
3 | let navbar = {}
4 | for (let lang of ['en', 'ru']) {
5 | let config = []
6 | for (let [relativePath, entry] of Object.entries(pages)) {
7 | const path = '/' + lang + relativePath
8 | config.push({
9 | text: entry.text[lang],
10 | children: entry.pages.map(r => path + r)
11 | })
12 | }
13 | navbar[lang] = config
14 | }
15 |
16 | export const navbarConfig = navbar
--------------------------------------------------------------------------------
/docs/docs/.vuepress/configs/pages.js:
--------------------------------------------------------------------------------
1 | import modules from './modules'
2 | export default {
3 | '/': {
4 | text: {'en': 'OwnLang', 'ru': 'OwnLang'},
5 | pages: [
6 | 'README.md',
7 | 'links.md',
8 | 'changelog.md',
9 | ]
10 | },
11 |
12 | '/basics/': {
13 | text: {'en': 'Basics', 'ru': 'Основы'},
14 | pages: [
15 | 'comments.md',
16 | 'strings.md',
17 | 'types.md',
18 | 'loops.md',
19 | 'functions.md',
20 | 'destructuring_assignment.md',
21 | 'pattern_matching.md',
22 | 'string_functions.md',
23 | 'array_functions.md'
24 | ]
25 | },
26 |
27 | '/modules/': {
28 | text: {'en': 'Modules', 'ru': 'Модули'},
29 | pages: modules
30 | }
31 | }
--------------------------------------------------------------------------------
/docs/docs/.vuepress/configs/sidebar.js:
--------------------------------------------------------------------------------
1 | import pages from './pages'
2 |
3 | let sidebar = {}
4 | for (let lang of ['en', 'ru']) {
5 | let config = {}
6 | for (let [relativePath, entry] of Object.entries(pages)) {
7 | const path = '/' + lang + relativePath
8 | config[path] = (path in config) ? config[path] : []
9 | config[path].push({
10 | text: entry.text[lang],
11 | children: entry.pages.map(r => path + r)
12 | })
13 | }
14 | sidebar[lang] = config
15 | }
16 |
17 | export const sidebarConfig = sidebar
--------------------------------------------------------------------------------
/docs/docs/.vuepress/styles/palette.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | --c-brand: #f15d15;
3 | --c-brand-light: #ff9562;
4 | --c-badge-danger: #f63f3f;
5 | --c-badge-warning: #d0af01;
6 |
7 | --usc-since: var(--c-badge-warning);
8 | --usc-scope: var(--c-brand);
9 | }
10 | html.dark {
11 | --c-brand: #e1792d;
12 | --c-brand-light: #ff8e3d;
13 | --c-badge-danger: #d94657;
14 | --c-badge-danger-text: #160304;
15 | }
--------------------------------------------------------------------------------
/docs/docs/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | title: OwnLang
4 | heroText: OwnLang
5 | tagline: Dynamic functional programming language
6 | actions:
7 | - text: English
8 | link: /en/
9 | type: primary
10 | - text: Русский
11 | link: /ru/
12 | type: primary
13 | footer: © 2024 aNNiMON
14 | ---
15 |
--------------------------------------------------------------------------------
/docs/docs/code/basics/destructuring_assignment1.own:
--------------------------------------------------------------------------------
1 | arr = ["a", "b", "c"]
2 | extract(var1, var2, var3) = arr
3 | print var1 // a
4 | print var2 // b
5 | print var3 // c
--------------------------------------------------------------------------------
/docs/docs/code/basics/destructuring_assignment2.own:
--------------------------------------------------------------------------------
1 | arr = ["a", "b", "c"]
2 | var1 = arr[0]
3 | var2 = arr[1]
4 | var3 = arr[2]
--------------------------------------------------------------------------------
/docs/docs/code/basics/destructuring_assignment3.own:
--------------------------------------------------------------------------------
1 | map = {"key1": 1, "test": "text"}
2 | extract(var1, var2) = map
3 | println var1 // [key1, 1]
4 | println var2 // [test, text]
--------------------------------------------------------------------------------
/docs/docs/code/basics/destructuring_assignment4.own:
--------------------------------------------------------------------------------
1 | extract(x, , z) = [93, 58, 90]
2 | println x // 93
3 | println z // 90
--------------------------------------------------------------------------------
/docs/docs/code/basics/fibonacci.own:
--------------------------------------------------------------------------------
1 | def fibonacci(count) {
2 | def fib(n) {
3 | if n < 2 return n
4 | return fib(n-2) + fib(n-1)
5 | }
6 | return fib(count)
7 | }
8 |
9 | println fibonacci(10) // 55
--------------------------------------------------------------------------------
/docs/docs/code/basics/loops1.own:
--------------------------------------------------------------------------------
1 | arr = [1, 2, 3, 4]
2 | for v : arr {
3 | println v
4 | }
5 |
6 | map = {"key1": 1, "key2": 2}
7 | for key, value : map
8 | println key + " = " value
9 | }
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching1.own:
--------------------------------------------------------------------------------
1 | x = 2
2 | print match x {
3 | case 1: "One"
4 | case 2: "Two"
5 | case "str": "String"
6 | case _: "Unknown"
7 | }
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching2.own:
--------------------------------------------------------------------------------
1 | x = "str"
2 | match x {
3 | case "": {
4 | println "Empty string"
5 | }
6 | case "str": {
7 | println "String!"
8 | }
9 | }
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching3.own:
--------------------------------------------------------------------------------
1 | def test(x) = match x {
2 | case a: "case a: " + a
3 | case b: "case b: " + b
4 | case c: "case c: " + c
5 | }
6 | a = 10
7 | b = 20
8 | println test(15) // case c: 15
9 | println test(20) // case b: 20
10 | println test("test") // case c: test
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching4.own:
--------------------------------------------------------------------------------
1 | def test(x) = match x {
2 | case x if x < 0: "(-∞ .. 0)"
3 | case x if x > 0: "(0 .. +∞)"
4 | case x: "0"
5 | }
6 |
7 | println test(-10) // (-∞ .. 0)
8 | println test(0) // 0
9 | println test(10) // (0 .. +∞)
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching5.own:
--------------------------------------------------------------------------------
1 | def arrayRecursive(arr) = match arr {
2 | case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
3 | case []: "[]"
4 | case last: "[" + last + ", []]"
5 | }
6 |
7 | println arrayRecursive([1, 2, 3, 4, 5, 6, 7]) // [1, [2, [3, [4, [5, [6, [7, []]]]]]]]
--------------------------------------------------------------------------------
/docs/docs/code/basics/pattern_matching6.own:
--------------------------------------------------------------------------------
1 | for i = 1, i <= 100, i++ {
2 | println match [i % 3 == 0, i % 5 == 0] {
3 | case (true, false): "Fizz"
4 | case (false, true): "Buzz"
5 | case (true, true): "FizzBuzz"
6 | case _: i
7 | }
8 | }
--------------------------------------------------------------------------------
/docs/docs/code/basics/string_functions1.own:
--------------------------------------------------------------------------------
1 | str = " ababcaab "
2 | println indexOf(str, "abc")
3 | println str.indexOf("abc")
4 |
5 | def isBlank(s) = s.trim().isEmpty()
6 | println isBlank(str)
7 | println str.isBlank()
--------------------------------------------------------------------------------
/docs/docs/code/functional_en.own:
--------------------------------------------------------------------------------
1 | use std, functional
2 |
3 | nums = [1,2,3,4,5,6,7,8,9,10]
4 | nums = filter(nums, def(x) = x % 2 == 0)
5 | // Squares of even numbers
6 | squares = map(nums, def(x) = x * x)
7 | foreach(squares, ::echo)
8 | // Sum of squares
9 | sum = reduce(squares, 0, def(x, y) = x + y)
10 | println "Sum: " + sum
11 | // Same using stream
12 | println "Sum: " + stream(range(1, 11))
13 | .filter(def(x) = x % 2 == 0)
14 | .map(def(x) = x * x)
15 | .reduce(0, def(x, y) = x + y)
16 |
--------------------------------------------------------------------------------
/docs/docs/code/functional_ru.own:
--------------------------------------------------------------------------------
1 | use std, functional
2 |
3 | nums = [1,2,3,4,5,6,7,8,9,10]
4 | nums = filter(nums, def(x) = x % 2 == 0)
5 | // Квадраты чётных чисел
6 | squares = map(nums, def(x) = x * x)
7 | foreach(squares, ::echo)
8 | // Сумма квадратов
9 | sum = reduce(squares, 0, def(x, y) = x + y)
10 | println "Сумма: " + sum
11 | // То же самое с использованием stream
12 | println "Сумма: " + stream(range(1, 11))
13 | .filter(def(x) = x % 2 == 0)
14 | .map(def(x) = x * x)
15 | .reduce(0, def(x, y) = x + y)
16 |
--------------------------------------------------------------------------------
/docs/docs/code/high_order_functions_en.own:
--------------------------------------------------------------------------------
1 | operations = {
2 | "+" : def(a,b) = a+b,
3 | "-" : def(a,b) = a-b,
4 | "*" : def(a,b) = a*b,
5 | "/" : ::division
6 | }
7 | def division(v1, v2) {
8 | if (v2 == 0) return "error: division by zero"
9 | return v1 / v2
10 | }
11 |
12 | for operation : operations {
13 | println operation(2, 3)
14 | }
--------------------------------------------------------------------------------
/docs/docs/code/high_order_functions_ru.own:
--------------------------------------------------------------------------------
1 | operations = {
2 | "+" : def(a,b) = a+b,
3 | "-" : def(a,b) = a-b,
4 | "*" : def(a,b) = a*b,
5 | "/" : ::division
6 | }
7 | def division(v1, v2) {
8 | if (v2 == 0) return "ошибка: деление на ноль"
9 | return v1 / v2
10 | }
11 |
12 | for operation : operations {
13 | println operation(2, 3)
14 | }
--------------------------------------------------------------------------------
/docs/docs/code/http_en.own:
--------------------------------------------------------------------------------
1 | use std, http, functional
2 |
3 | // GET request
4 | http("https://api.github.com/events", def(r) {
5 | use json
6 | events = jsondecode(r)
7 | })
8 |
9 | // POST request
10 | http("http://jsonplaceholder.typicode.com/users", "POST", {
11 | "name": "OwnLang",
12 | "versionCode": 10
13 | }, ::echo)
14 |
15 | // PATCH request
16 | http("http://jsonplaceholder.typicode.com/users/2", "PATCH", {"name": "Patched Name"}, ::patch_callback)
17 |
18 | def patch_callback(v) {
19 | println v
20 | }
21 |
--------------------------------------------------------------------------------
/docs/docs/code/http_ru.own:
--------------------------------------------------------------------------------
1 | use std, http, functional
2 |
3 | // GET-запрос
4 | http("https://api.github.com/events", def(r) {
5 | use json
6 | events = jsondecode(r)
7 | })
8 |
9 | // POST-запрос
10 | http("http://jsonplaceholder.typicode.com/users", "POST", {
11 | "name": "OwnLang",
12 | "versionCode": 10
13 | }, ::echo)
14 |
15 | // PATCH-запрос
16 | http("http://jsonplaceholder.typicode.com/users/2", "PATCH", {"name": "Патч"}, ::patch_callback)
17 |
18 | def patch_callback(v) {
19 | println v
20 | }
21 |
--------------------------------------------------------------------------------
/docs/docs/code/operator_overloading.own:
--------------------------------------------------------------------------------
1 | use std, types, math
2 |
3 | def `..`(a, b) = range(a, b - 1)
4 | def `**`(a, b) = int(pow(a, b))
5 | for y : 1 .. 10 {
6 | println sprintf("2 ^ %d = %d", y, 2 ** y)
7 | }
--------------------------------------------------------------------------------
/docs/docs/code/pattern_matching.own:
--------------------------------------------------------------------------------
1 | def factorial(n) = match n {
2 | case 0: 1
3 | case n if n < 0: 0
4 | case _: n * factorial(n - 1)
5 | }
6 |
7 | def fizzbuzz(limit = 100) {
8 | for i = 1, i <= limit, i++ {
9 | println match [i % 3 == 0, i % 5 == 0] {
10 | case (true, false): "Fizz"
11 | case (false, true): "Buzz"
12 | case (true, true): "FizzBuzz"
13 | case _: i
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/docs/docs/en/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | OwnLang — dynamic functional programming language inspired by Scala and Python. Available for PC and Android devices.
4 |
5 | ## Key features
6 |
7 | ### Higher-order functions
8 |
9 | Functions are values, so we can store them to variables for operating.
10 |
11 | @[code](../code/high_order_functions_en.own)
12 |
13 | ### Pattern Matching
14 |
15 | Pattern matching with value pattern, tuple pattern, list pattern and optional condition.
16 |
17 | @[code](../code/pattern_matching.own)
18 |
19 | ### Functional data operations
20 |
21 | Operate data in functional style.
22 |
23 | @[code](../code/functional_en.own)
24 |
25 | ### Operator overloading
26 |
27 | Why not?
28 |
29 | @[code](../code/operator_overloading.own)
30 |
31 | ### Network module
32 |
33 | Easy async HTTP requests with `http` module.
34 |
35 | @[code](../code/http_en.own)
--------------------------------------------------------------------------------
/docs/docs/en/basics/README.md:
--------------------------------------------------------------------------------
1 | # Basics
2 |
3 | * [Comments](comments.md)
4 | * [Strings](strings.md)
5 | * [Types](types.md)
6 | * [Loops](loops.md)
7 | * [Functions definition](functions.md)
8 | * [Destructuring assignment](destructuring_assignment.md)
9 | * [Pattern matching](pattern_matching.md)
10 | * [String functions](string_functions.md)
11 | * [Array functions](array_functions.md)
12 |
--------------------------------------------------------------------------------
/docs/docs/en/basics/array_functions.md:
--------------------------------------------------------------------------------
1 | # Array functions
2 |
3 | Fields:
4 | - `length` - number of elements of the array
5 |
6 | Functions:
7 | - `isEmpty()` - returns true, if the array is empty
8 | - `joinToString(delimiter = "", prefix = "", suffix = "")` - joins array into a string
9 |
--------------------------------------------------------------------------------
/docs/docs/en/basics/comments.md:
--------------------------------------------------------------------------------
1 | # Comments
2 |
3 | ```own
4 | // Line comment
5 | /* multiline
6 | comment
7 | */
8 | print /*inner comment*/ "Text"
9 | ```
--------------------------------------------------------------------------------
/docs/docs/en/basics/destructuring_assignment.md:
--------------------------------------------------------------------------------
1 | # Destructuring assignment
2 |
3 | Destructuring assignment allows to define multiple variables for each element of an array or map.
4 |
5 | For arrays, value is assigned to variable:
6 |
7 | @[code](../../code/basics/destructuring_assignment1.own)
8 |
9 | Which is equivalent to:
10 |
11 | @[code](../../code/basics/destructuring_assignment2.own)
12 |
13 | For maps, key and value are assigned to variable:
14 |
15 | @[code](../../code/basics/destructuring_assignment3.own)
16 |
17 | To skip value just leave argument empty:
18 |
19 | @[code](../../code/basics/destructuring_assignment4.own)
20 |
--------------------------------------------------------------------------------
/docs/docs/en/basics/functions.md:
--------------------------------------------------------------------------------
1 | # Functions definition
2 |
3 | To define function uses the `def` keyword:
4 |
5 | ```own
6 | def function(arg1, arg2) {
7 | println arg1
8 | }
9 | ```
10 |
11 | ## Shorthand definition
12 |
13 | There is short syntax fot function body:
14 |
15 | ```own
16 | def repeat(str, count) = str * count
17 | ```
18 |
19 | Which is equivalent to:
20 |
21 | ```own
22 | def repeat(str, count) {
23 | return str * count
24 | }
25 | ```
26 |
27 | ## Default arguments
28 |
29 | Function arguments can have default values.
30 |
31 | ```own
32 | def repeat(str, count = 5) = str * count
33 | ```
34 |
35 | In this case only `str` argument is required.
36 |
37 | ```own
38 | repeat("*") // *****
39 | repeat("+", 3) // +++
40 | ```
41 |
42 | Default arguments can't be declared before required arguments.
43 |
44 | ```own
45 | def repeat(str = "*", count) = str * count
46 | ```
47 |
48 | Causes parsing error: `ParseError on line 1: Required argument cannot be after optional`
49 |
50 | ## Inner functions
51 |
52 | You can define function in other function.
53 |
54 | @[code](../../code/basics/fibonacci.own)
55 |
--------------------------------------------------------------------------------
/docs/docs/en/basics/string_functions.md:
--------------------------------------------------------------------------------
1 | # String functions
2 |
3 | Fields:
4 | - `length` - string length
5 | - `lower` - lower case string
6 | - `upper` - upper case string
7 | - `chars` - ASCII characters array
8 |
9 | Functions:
10 | - `trim()` - removes any leading and trailing whitespaces in string
11 | - `startsWith(str, offset = 0)` - checks whether the string starts with the substring str at offset
12 | - `endsWith(str)` - checks whether the string ends with the str
13 | - `matches(regex)` - checks whether the string matches regex pattern
14 | - `contains(str)` - checks whether the string contains substring str
15 | - `equalsIgnoreCase(str)` - checks equality of two strings ignore case (tEsT = TEST)
16 | - `isEmpty()` - returns true, if the string is empty
17 |
18 | In addition, there are automatic function extensions available if the function accepts a string as the first argument:
19 |
20 | @[code](../../code/basics/string_functions1.own)
21 |
--------------------------------------------------------------------------------
/docs/docs/en/basics/strings.md:
--------------------------------------------------------------------------------
1 | # Strings
2 |
3 | Strings are defined in double quotes and can be multiline. Escaping Unicode characters is also supported.:
4 |
5 | ```own
6 | str = "\n\tThis is
7 | \tmultiline
8 | \ttext
9 | "
10 | ```
11 |
12 | `print` and `println` operators are used to output text.
--------------------------------------------------------------------------------
/docs/docs/en/basics/types.md:
--------------------------------------------------------------------------------
1 | # Types
2 |
3 | OwnLang types are:
4 |
5 | * Number - numbers (integer, float)
6 | * String - strings
7 | * Array - arrays
8 | * Map - objects (an associative arrays)
9 | * Function - functions
10 | * Class
11 |
12 | Since OwnLang is dynamic programming language, which means that explicitly declare the types is not necessary.
13 |
14 | ```own
15 | x = 10 // integer
16 | y = 1.61803 // float
17 | z = "abcd" // string
18 | ```
19 |
20 | If some function requires string as argument, but number was passed, then numeric value will automatically converts to string.
21 |
22 | ```own
23 | x = 90
24 | print x // Ok, 90 converts to "90"
25 | ```
--------------------------------------------------------------------------------
/docs/docs/en/links.md:
--------------------------------------------------------------------------------
1 | # Links
2 |
3 | ## Downloads
4 |
5 | Android: [Free](https://play.google.com/store/apps/details?id=com.annimon.ownlang.free) / [Pro](https://play.google.com/store/apps/details?id=com.annimon.ownlang)
6 | PC / Netbeans Plugin / etc: [GitHub Releases](https://github.com/aNNiMON/Own-Programming-Language-Tutorial/releases)
7 | Source code: [GitHub](https://github.com/aNNiMON/Own-Programming-Language-Tutorial)
8 |
9 | Also available as AUR package:
10 |
11 | ```
12 | paru -S ownlang
13 | ```
14 |
--------------------------------------------------------------------------------
/docs/docs/ru/README.md:
--------------------------------------------------------------------------------
1 | # Возможности
2 |
3 | OwnLang — скриптовый функциональный язык программирования с динамической типизацией для ПК и Android устройств.
4 |
5 | ## Ключевые особенности
6 |
7 | ### Функции высшего порядка
8 |
9 | Функции выступают как значения, а значит мы можем сохранять их в переменные для дальнейшего использования.
10 |
11 | @[code](../code/high_order_functions_ru.own)
12 |
13 | ### Pattern Matching
14 |
15 | Сопоставление по образцу с шаблоном значений, шаблоном кортежей, шаблоном списков и дополнительным сравнением.
16 |
17 | @[code](../code/pattern_matching.own)
18 |
19 | ### Функциональные операции над данными
20 |
21 | Оперирование данными в функциональном стиле.
22 |
23 | @[code](../code/functional_ru.own)
24 |
25 | ### Перегрузка операторов
26 |
27 | Почему бы и нет?
28 |
29 | @[code](../code/operator_overloading.own)
30 |
31 | ### Модуль для работы с сетью Интернет
32 |
33 | Простые асинхронные HTTP-запросы с модулем `http`.
34 |
35 | @[code](../code/http_ru.own)
--------------------------------------------------------------------------------
/docs/docs/ru/basics/README.md:
--------------------------------------------------------------------------------
1 | # Синтаксис и основы языка
2 |
3 | * [Комментарии](comments.md)
4 | * [Строки](strings.md)
5 | * [Типы](types.md)
6 | * [Циклы](loops.md)
7 | * [Определение функций](functions.md)
8 | * [Реструктуризующее присваивание](destructuring_assignment.md)
9 | * [Pattern matching](pattern_matching.md) (сопоставление с образцом)
10 | * [Функции строк](string_functions.md)
11 | * [Функции массивов](array_functions.md)
--------------------------------------------------------------------------------
/docs/docs/ru/basics/array_functions.md:
--------------------------------------------------------------------------------
1 | # Функции массивов
2 |
3 | Поля:
4 | - `length` - количество элементов массива
5 |
6 | Функции:
7 | - `isEmpty()` - возвращает true, если массив пуст
8 | - `joinToString(delimiter = "", prefix = "", suffix = "")` - склеивает массив в строку
9 |
--------------------------------------------------------------------------------
/docs/docs/ru/basics/comments.md:
--------------------------------------------------------------------------------
1 | # Комментарии
2 |
3 | ```own
4 | // Однострочный комментарий
5 | /* многострочный
6 | комментарий
7 | */
8 | print /*или так*/ "Текст"
9 | ```
--------------------------------------------------------------------------------
/docs/docs/ru/basics/destructuring_assignment.md:
--------------------------------------------------------------------------------
1 | # Реструктуризующее присваивание
2 |
3 | Реструктуризующее (деструктивное) присваивание позволяет определить сразу несколько переменных по каждому элементу массива или объекта.
4 |
5 | Для массивов, переменным присваивается значение.
6 |
7 | @[code](../../code/basics/destructuring_assignment1.own)
8 |
9 | Что равносильно:
10 |
11 | @[code](../../code/basics/destructuring_assignment2.own)
12 |
13 | Для объектов, переменным присваивается массив [ключ, значение]
14 |
15 | @[code](../../code/basics/destructuring_assignment3.own)
16 |
17 | Если нужно пропустить какое-либо значение, название переменной можно не писать:
18 |
19 | @[code](../../code/basics/destructuring_assignment4.own)
--------------------------------------------------------------------------------
/docs/docs/ru/basics/functions.md:
--------------------------------------------------------------------------------
1 | # Определение функций
2 |
3 | Для определения функции используется ключевое слово `def`. Затем идёт имя, аргументы и тело функции. Пример:
4 |
5 | ```own
6 | def function(arg1, arg2) {
7 | println arg1
8 | }
9 | ```
10 |
11 | ## Короткий синтаксис
12 |
13 | Возможен короткий синтаксис:
14 |
15 | ```own
16 | def repeat(str, count) = str * count
17 | ```
18 |
19 | что равносильно:
20 |
21 | ```own
22 | def repeat(str, count) {
23 | return str * count
24 | }
25 | ```
26 |
27 | ## Аргументы по умолчанию
28 |
29 | Аргументы функции могут иметь значения по умолчанию.
30 |
31 | ```own
32 | def repeat(str, count = 5) = str * count
33 | ```
34 |
35 | В этом случае обязательным будет только аргумент `str`
36 |
37 | ```own
38 | repeat("*") // *****
39 | repeat("+", 3) // +++
40 | ```
41 |
42 | Аргументы по умолчанию обязательно должны идти после обязательных аргументов, если такие были.
43 |
44 | ```own
45 | def repeat(str = "*", count) = str * count
46 | ```
47 |
48 | Приведёт к ошибки парсинга: `ParseError on line 1: Required argument cannot be after optional`
49 |
50 | ## Внутренние функции
51 |
52 | Внутри функции можно объявить другую функцию.
53 |
54 | @[code](../../code/basics/fibonacci.own)
--------------------------------------------------------------------------------
/docs/docs/ru/basics/string_functions.md:
--------------------------------------------------------------------------------
1 | # Функции строк
2 |
3 | Поля:
4 | - `length` - длина строки
5 | - `lower` - строка в нижнем регистре
6 | - `upper` - строка в верхнем регистре
7 | - `chars` - массив символов в виде ASCII-кодов
8 |
9 | Функции:
10 | - `trim()` - обрезает пробельные невидимые символы по обоим концам строки
11 | - `startsWith(str, offset = 0)` - проверяет, начинается ли строка с подстроки str в позиции offset
12 | - `endsWith(str)` - проверяет, заканчивается ли строка подстрокой str
13 | - `matches(regex)` - проверяет соответствие строки с заданным шаблоном
14 | - `contains(str)` - проверяет, содержится ли в строке подстрока str
15 | - `equalsIgnoreCase(str)` - проверяет, равны ли строки вне зависимости от регистра (tEsT = TEST)
16 | - `isEmpty()` - возвращает true, если строка пустая
17 |
18 | Кроме того, доступны автоматические функции-расширения, если функция принимает в качестве первого аргумента строку:
19 |
20 | @[code](../../code/basics/string_functions1.own)
21 |
--------------------------------------------------------------------------------
/docs/docs/ru/basics/strings.md:
--------------------------------------------------------------------------------
1 | # Строки
2 |
3 | Строки задаются в двойных кавычках и могут быть многострочные. Поддерживается юникод и экранирование символов:
4 |
5 | ```own
6 | str = "\n\tЭто
7 | \tмногострочный
8 | \tтекст
9 | "
10 | ```
11 |
12 | Для вывода строк есть два оператора `print` и `println`
--------------------------------------------------------------------------------
/docs/docs/ru/basics/types.md:
--------------------------------------------------------------------------------
1 | # Типы
2 |
3 | В OwnLang есть такие типы:
4 |
5 | * Number - числа (охватывает как целые, так и вещественные числа)
6 | * String - строки
7 | * Array - массивы
8 | * Map - объекты (ассоциативные массивы)
9 | * Function - функции
10 | * Class - классы
11 |
12 | Поскольку OwnLang - динамически типизируемый язык программирования, это значит, что явно объявлять типы не нужно.
13 |
14 | ```own
15 | x = 10 // целое число
16 | y = 1.61803 // вещественное число
17 | z = "abcd" // строка
18 | ```
19 |
20 | Если какая-либо функция предполагает использование строк в качестве аргументов, а были переданы числа, то значения автоматически приведутся к строке.
21 |
22 | ```own
23 | x = 90
24 | print x
25 | ```
--------------------------------------------------------------------------------
/docs/docs/ru/links.md:
--------------------------------------------------------------------------------
1 | # Ссылки
2 |
3 | ## Загрузки
4 |
5 | Android: [Free](https://play.google.com/store/apps/details?id=com.annimon.ownlang.free) / [Pro](https://play.google.com/store/apps/details?id=com.annimon.ownlang)
6 | PC / плагин Netbeans / прочее: [GitHub Releases](https://github.com/aNNiMON/Own-Programming-Language-Tutorial/releases)
7 | Исходный код: [GitHub](https://github.com/aNNiMON/Own-Programming-Language-Tutorial)
8 |
9 | Также доступно в виде пакета в AUR:
10 |
11 | ```
12 | paru -S ownlang
13 | ```
14 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ownlang-docs",
3 | "version": "1.0.0",
4 | "description": "OwnLang Documentation",
5 | "main": "index.js",
6 | "scripts": {
7 | "docs:dev": "vuepress dev docs",
8 | "docs:build": "vuepress build docs"
9 | },
10 | "keywords": [
11 | "documentation",
12 | "ownlang",
13 | "programming-language"
14 | ],
15 | "author": "aNNiMON",
16 | "license": "MIT",
17 | "devDependencies": {
18 | "@vuepress/client": "2.0.0-rc.0",
19 | "@vuepress/plugin-prismjs": "2.0.0-rc.0",
20 | "@vuepress/plugin-register-components": "2.0.0-rc.0",
21 | "@vuepress/plugin-search": "2.0.0-rc.0",
22 | "@vuepress/utils": "2.0.0-rc.0",
23 | "prismjs": "^1.30.0",
24 | "vue": "^3.4.20",
25 | "vuepress": "2.0.0-rc.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/src/modules/base64.yml:
--------------------------------------------------------------------------------
1 | name: base64
2 | scope: both
3 | desc: "Contains base64 encoding and decoding functions"
4 | desc_ru: "Содержит функции кодирования данных в base64 и наоборот"
5 | constants:
6 | - name: BASE64_URL_SAFE
7 | type: 1
8 | typeName: number
9 | value: '8'
10 | desc: 'Url safe encoding output'
11 | desc_ru: 'Вывод данных в безопасном для ссылок формате'
12 | functions:
13 | - name: base64decode
14 | args: 'data, type = 0'
15 | desc: 'decodes base64-encoded byte array or string into byte array'
16 | desc_ru: 'декодирует массив байт или строку, закодированную в base64, в массив байт'
17 | - name: base64encode
18 | args: 'data, type = 0'
19 | desc: 'encodes byte array or string into base64-encoded byte array'
20 | desc_ru: 'кодирует массив байт или строку в закодированный base64 массив байт'
21 | - name: base64encodeToString
22 | args: 'data, type = 0'
23 | desc: 'encodes byte array or string into base64-encoded string'
24 | desc_ru: 'кодирует массив байт или строку в закодированную base64 строку'
--------------------------------------------------------------------------------
/docs/src/modules/downloader.yml:
--------------------------------------------------------------------------------
1 | name: downloader
2 | scope: both
3 | desc: "Contains functions for downloading large files"
4 | desc_ru: "Содержит функции для скачивания больших файлов"
5 | functions:
6 | - name: getContentLength
7 | args: 'url'
8 | desc: 'gets content length by sending HEAD request to the given url'
9 | desc_ru: 'получает значение заголовка Content-Length путём отправки HEAD-запроса на указанный url'
10 | - name: downloader
11 | args: 'downloadUrl, filePath, progressCallback = def() {}, bufferSize = 16384'
12 | desc: 'downloads file from `downloadUrl` to `filePath`'
13 | desc_ru: 'скачивает файл по адресу `downloadUrl` и сохраняет в `filePath`'
14 | example: |-
15 | use downloader, std
16 |
17 | MBYTES = 1048576.0 // 1024*1024
18 | url = "http://www.ovh.net/files/10Mb.dat"
19 | file = "10Mb.dat"
20 |
21 | downloader(url, file, def(progress, bytesDownloaded, bytesMax) {
22 | bar = "#" * (progress / 2)
23 | print sprintf("%-50s %d%% %.2f / %.2f MiB\\r", bar, progress, bytesDownloaded / MBYTES, bytesMax / MBYTES)
24 | })
--------------------------------------------------------------------------------
/docs/src/modules/json.yml:
--------------------------------------------------------------------------------
1 | name: json
2 | scope: "both"
3 | desc: "Contains functions for working with the json format"
4 | desc_ru: "Содержит функции преобразования данных в формат json и наоборот"
5 | constants: []
6 | functions:
7 | - name: "jsondecode"
8 | args: "data"
9 | desc: "converts data to json string"
10 | desc_ru: "преобразует переданные данные в строку в формате json"
11 | example: |-
12 | use json
13 | print jsondecode("{\"key1\":1,\"key2\":[1,2,3],\"key3\":\"text\"}") // {key2=[1, 2, 3], key3=text, key1=1}
14 | - name: "jsonencode"
15 | args: "jsonString, indent = 0"
16 | desc: "converts string to data"
17 | desc_ru: "преобразует строку в формате json в данные"
18 | example: |-
19 | use json
20 | data = {
21 | "key1": 1,
22 | "key2": [1, 2, 3],
23 | "key3": "text"
24 | }
25 | print jsonencode(data) // {"key1":1,"key2":[1,2,3],"key3":"text"}
--------------------------------------------------------------------------------
/docs/src/modules/yaml.yml:
--------------------------------------------------------------------------------
1 | name: yaml
2 | scope: desktop
3 | desc: "Contains functions for working with the yaml format"
4 | desc_ru: "Содержит функции преобразования данных в формат yaml и наоборот"
5 | constants: []
6 | functions:
7 | - name: yamldecode
8 | args: "data"
9 | desc: "converts data to yaml string"
10 | desc_ru: "преобразует переданные данные в строку в формате yaml"
11 | - name: yamlencode
12 | args: "yamlString"
13 | desc: "converts yaml string to data"
14 | desc_ru: "преобразует строку в формате yaml в данные"
--------------------------------------------------------------------------------
/editors/README.md:
--------------------------------------------------------------------------------
1 | # Syntax for Editors
2 |
3 | ## Intellij IDEA
4 |
5 | 1. Open an `idea` folder
6 | 2. Add all files and folders to zip archive, e.g. `settings.zip`
7 | 3. File -> Manage IDE Settings -> Import. Select your zip file.
8 |
9 | ## Prism.js
10 |
11 | ```javascript
12 | import Prism from 'prismjs';
13 | import definePrismOwnLang from './prismjs/own-language.js'
14 | definePrismOwnLang(Prism)
15 | ```
16 |
17 | ## GTKSourceView
18 |
19 | Place `ownlang.lang` in `/usr/share/gtksourceview-3.0/language-specs/ownlang.lang`
--------------------------------------------------------------------------------
/editors/highlighjs/own.js:
--------------------------------------------------------------------------------
1 | export default function(hljs) {
2 | const STRING = {
3 | className: 'string',
4 | variants: [{
5 | begin: '"', end: '"',
6 | contains: [hljs.BACKSLASH_ESCAPE]
7 | }]
8 | };
9 |
10 | const EXTENDED_LITERAL = {
11 | className: 'literal',
12 | variants: [{
13 | begin: '`', end: '`',
14 | illegal: '\\n'
15 | }]
16 | };
17 |
18 | const METHOD = {
19 | className: 'function',
20 | beginKeywords: 'def',
21 | end: /[:={\[(\n;]/,
22 | excludeEnd: true,
23 | contains: [{
24 | className: 'title',
25 | begin: /[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,
26 | relevance: 0
27 | }]
28 | };
29 |
30 | return {
31 | keywords: {
32 | literal: 'true false this null',
33 | keyword: 'break class continue def else for if match print println return use while do case extract include'
34 | },
35 | contains: [
36 | hljs.C_LINE_COMMENT_MODE,
37 | hljs.C_BLOCK_COMMENT_MODE,
38 | STRING,
39 | EXTENDED_LITERAL,
40 | METHOD,
41 | hljs.C_NUMBER_MODE
42 | ]
43 | };
44 | };
--------------------------------------------------------------------------------
/editors/idea/IntelliJ IDEA Global Settings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aNNiMON/Own-Programming-Language-Tutorial/f9c2bff15962b60ddc2d5b94a7f35d18e9b06900/editors/idea/IntelliJ IDEA Global Settings
--------------------------------------------------------------------------------
/editors/idea/filetypes/OwnLang.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/editors/prismjs/own-language.js:
--------------------------------------------------------------------------------
1 | export default function(Prism) {
2 | Prism.languages.own = Prism.languages.extend('clike', {
3 | 'string': {
4 | pattern: /(^|[^\\])"(?:\\.|[^"\\])*"/,
5 | lookbehind: true,
6 | greedy: true
7 | },
8 | 'keyword': /\b(?:break|case|class|continue|def|do|else|extract|for|if|include|match|new|print|println|return|while|use)\b/,
9 | 'function': {
10 | pattern: /((?:^|\s)def\s*)([a-zA-Z_]\w*)?(?=\s*\()/g,
11 | lookbehind: true
12 | },
13 | 'operator': {
14 | pattern: /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\*\*|\|\||::|\.\.\.?|[?:~]|[-+*/%&|^!=<>]=?)/m,
15 | lookbehind: true
16 | },
17 | 'punctuation': /[{}[\];(),.:`]/
18 | });
19 | }
--------------------------------------------------------------------------------
/examples/basics/array.own:
--------------------------------------------------------------------------------
1 | arr1 = [1, 2, 3, 4, 5]
2 | println arr1[0]
3 | println arr1[1]
4 | println arr1
5 |
6 | use std
7 | arr2 = newarray(5)
8 | arr2[2] = 9
9 | arr2 = arr2 :: 4
10 | println arr2
11 |
12 | // Append array
13 | arr3 = arr1 :: arr2
14 | println arr3
15 | // Merge array
16 | arr4 = arr1 << arr2
17 | println arr4
18 |
19 |
20 | // Array 2d
21 | arr5 = newarray(4, 4)
22 | println arr5
23 | arr5[1] = arr1
24 | println arr5
25 |
26 | arr6 = [arr5[1], arr5[2]]
27 | println arr6
--------------------------------------------------------------------------------
/examples/basics/bitwise_operators.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | echo(#ABCDEF - #12345)
4 | echo(-8 << 2)
5 | echo(-8 >> 2)
6 | echo(-8 >>> 2)
7 |
8 | echo()
9 | for a = 0, a <= 1, a++ {
10 | for b = 0, b <= 1, b++ {
11 | echo(a, " | ", b, " ", a | b)
12 | echo(a, " & ", b, " ", a & b)
13 | echo(a, " ^ ", b, " ", a ^ b)
14 | }
15 | echo(" ~", a, " ", ~a)
16 | echo(" !", a, " ", !a)
17 | }
--------------------------------------------------------------------------------
/examples/basics/classes.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | class Point {
4 | def Point(x = 0, y = 0) {
5 | this.x = x
6 | this.y = y
7 | }
8 |
9 | def moveBy(p) {
10 | this.move(p.x, p.y)
11 | }
12 |
13 | def move(dx, dy) {
14 | this.x += dx
15 | this.y += dy
16 | }
17 |
18 | def toString() = "(" + this.x + ", " + this.y + ")"
19 | }
20 |
21 | p = new Point(20, 30)
22 | p.move(10, -5)
23 | println p.toString()
24 |
25 | p2 = new Point(1, 1)
26 | p2.moveBy(p)
27 | println p2.toString()
28 |
--------------------------------------------------------------------------------
/examples/basics/destructuring_assignment.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | println "Destructuring assignment"
4 | arr = ["a", "b", "c"]
5 | extract(var1, var2, var3) = arr
6 | echo(var1, var2, var3)
7 |
8 | // Swap
9 | println "Swap variables"
10 | echo(var1, var2)
11 | extract(var2, var1) = [var1, var2]
12 | echo(var1, var2)
--------------------------------------------------------------------------------
/examples/basics/extended_identifier.own:
--------------------------------------------------------------------------------
1 | `extended identifier variable` = 9
2 | println `extended identifier variable`
3 |
4 | `(。◕‿◕。)` = 20
5 | `ʕ•ᴥ•ʔ` = 30
6 | println `(。◕‿◕。)` * `ʕ•ᴥ•ʔ`
--------------------------------------------------------------------------------
/examples/basics/loops.own:
--------------------------------------------------------------------------------
1 | // While loop
2 | println "While loop"
3 | a = 0
4 | while a < 3 {
5 | print a
6 | a++
7 | }
8 |
9 |
10 | // Do-while loop
11 | println "\n\nDo-while loop"
12 | a = 0
13 | do {
14 | print a
15 | a++
16 | } while (a < 3)
17 |
18 |
19 | // For loop
20 | println "\n\nFor loop"
21 | for a = 0, a < 10, a++
22 | print a
23 |
24 |
25 | // Foreach loop
26 | println "\n\nForeach loop on array"
27 | arr = [1, 2, 3, 4, 5]
28 | for a : arr
29 | print a
30 |
31 | use std
32 | println "\n\nForeach loop on map"
33 | object = {"key1": "value1", "key2": 100, "arr": [0, 1]}
34 | for key, value : object
35 | echo(key, ":", value)
36 |
37 |
38 | use functional
39 |
40 | // Functional loop
41 | println "\n\nFunctional loop on array"
42 | foreach(arr, ::echo)
43 | foreach(arr, def(v) {
44 | print v
45 | })
46 |
47 | println "\n\nFunctional loop on map"
48 | foreach(object, ::echo)
49 | foreach(object, def(k, v) {
50 | print " " + k + " : " + v
51 | })
52 | println ""
53 |
54 | // Range loop
55 | println "\n\nRange loop"
56 | for x : range(10) {
57 | print x
58 | }
--------------------------------------------------------------------------------
/examples/basics/map.own:
--------------------------------------------------------------------------------
1 | map1 = {"key": "value"}
2 | println map1["key"]
3 | println map1.key
4 |
5 | map1["newkey"] = "newvalue"
6 | map1[0] = "zero"
7 | x = 400
8 | map1[x] = [1, 2, 3]
9 | println map1
--------------------------------------------------------------------------------
/examples/basics/operator_overloading.own:
--------------------------------------------------------------------------------
1 | use std, types, math
2 |
3 | println "Operator overloading"
4 | def `::`(v1, v2) = string(v1) + string(v2)
5 | print "1 :: 2 :: 3 = "
6 | println 1 :: 2 :: 3
7 |
8 | def `^`(v1, v2) = pow(v1[0], v2[0])
9 | print "[2] ^ [7] = "
10 | println [2] ^ [7]
11 |
12 | def `..`(a, b) = range(a, b)
13 | def `**`(a, b) = int(pow(a, b))
14 | for y : 1 .. 10 {
15 | println sprintf("2 ^ %d = %d", y, 2 ** y)
16 | }
--------------------------------------------------------------------------------
/examples/basics/ternary_operator.own:
--------------------------------------------------------------------------------
1 | println "Ternary operator"
2 | a = 0
3 | b = 1
4 | println (a ? "text1" : "text2")
5 | println (b ? "text3" : "text4")
--------------------------------------------------------------------------------
/examples/basics/thread.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def thread1() {
4 | i = 0
5 | while (i < 100) {
6 | println "i = " + i
7 | i++
8 | sleep(100)
9 | }
10 | }
11 |
12 | // thread("thread1")
13 | thread(::thread1)
14 |
15 | k = 0
16 | while (k < 10) {
17 | println "k = " + k
18 | k++
19 | sleep(1000)
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/examples/basics/types.own:
--------------------------------------------------------------------------------
1 | use std, types
2 |
3 | println typeof(1)
4 | println typeof("1")
5 | println typeof([])
6 | println typeof({})
7 | println typeof(def() = 0)
8 |
9 | println typeof(number("1"))
10 | println typeof(string(1))
11 |
--------------------------------------------------------------------------------
/examples/canvas/1.own:
--------------------------------------------------------------------------------
1 | use canvas
2 |
3 | w = 800 h = 600
4 | window("canvas example", w, h);
5 |
6 | // Очистка экрана белым цветом
7 | color(#ffffff)
8 | frect(0, 0, w, h)
9 |
10 | // Рисуем две линии красным цветом
11 | color(#ff0000)
12 | line(0, 0, w, h)
13 | line(w, 0, 0, h)
14 | repaint()
15 |
--------------------------------------------------------------------------------
/examples/canvas/2.own:
--------------------------------------------------------------------------------
1 | use std, canvas
2 |
3 | w = 800 h = 600
4 | window("canvas example 2", w, h);
5 | color(#ffffff)
6 | frect(0, 0, w, h)
7 |
8 | step = rand(20)
9 | color(#0000ff)
10 | for y = 0, y < h, y += step {
11 | line(0, y, w, y)
12 | }
13 | for x = 0, x < w, x += step {
14 | line(x, 0, x, h)
15 | }
16 | repaint();
17 |
--------------------------------------------------------------------------------
/examples/canvas/control_point.own:
--------------------------------------------------------------------------------
1 | use canvas, std
2 |
3 | w = 640 h = 480
4 | window("Управление точкой", w, h)
5 |
6 | x = rand(w) y = rand(h)
7 |
8 | run = 1
9 | while run {
10 | key = keypressed()
11 | if (key == VK_LEFT && x > 0) x--
12 | else if (key == VK_RIGHT && x < w) x++
13 | else if (key == VK_UP && y > 0) y--
14 | else if (key == VK_DOWN && y < h) y++
15 | else if key == VK_ESCAPE run = 0
16 |
17 | color(255,255,255)
18 | frect(0,0,w,h)
19 | color(0)
20 | line(0, h, x, y)
21 | line(w, h, x, y)
22 | repaint()
23 | sleep(10)
24 | }
--------------------------------------------------------------------------------
/examples/canvas/fractal_polygon.own:
--------------------------------------------------------------------------------
1 | use canvas, math, std
2 |
3 | msg = ""
4 | NUM_POINTS = 0
5 | while (NUM_POINTS <= 2 || NUM_POINTS > 25) {
6 | NUM_POINTS = 0 + prompt("Сколькиугольник? (3..25)" + msg)
7 | if (NUM_POINTS <= 2) msg = "!! Сказано же, ну!"
8 | else if (NUM_POINTS > 25) msg = " Чувак, " + NUM_POINTS + " это будет ООООЧЕНЬ долго!"
9 | }
10 | angle = 2*PI / NUM_POINTS;
11 | DIVIDER = 2.8
12 |
13 |
14 | w = 800 h = 600
15 | window("Fractal polygon demo", w, h)
16 | fractal(w/2, h/2, w/2)
17 | repaint()
18 |
19 | def cpoly(cx, cy, size) {
20 | ox = cx oy = cy - size
21 | ang = 0
22 | for i = 0, i < NUM_POINTS, i++ {
23 | ang += angle
24 | nx = cx - sin(ang)*size ny = cy - cos(ang)*size
25 | line(ox, oy, nx, ny)
26 | ox = nx oy = ny
27 | }
28 | }
29 |
30 | def fractal(cx, cy, size) {
31 | if size >= 3 {
32 | s2 = size / 2
33 | sD = size / DIVIDER
34 | color(0, 0, 255 - size * 255 / w/2)
35 | cpoly(cx, cy, sD)
36 | fractal(cx, cy - s2, sD)
37 | for n = 0, n < NUM_POINTS, n++ {
38 | fractal(cx - sin(angle*n)*s2, cy - cos(angle*n)*s2, sD)
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/examples/canvas/fractal_rect.own:
--------------------------------------------------------------------------------
1 | use canvas
2 |
3 | w = 800 h = 600
4 | window("Fractal rectangle demo", w, h)
5 | fractal(w/2, h/2, w/2)
6 | repaint()
7 |
8 | def rect(x, y, w, h) {
9 | line(x, y, x + w, y)
10 | line(x + w, y, x + w, y + h)
11 | line(x, y + h, x + w, y + h)
12 | line(x, y, x, y + h)
13 | }
14 |
15 | def fractal(cx, cy, size) {
16 | if size >= 2 {
17 | s2 = size / 2
18 | color(0, 0, 255 - size * 255 / w/2)
19 | rect(cx-s2, cy-s2, size, size)
20 | fractal(cx-s2, cy-s2, s2)
21 | fractal(cx+s2, cy-s2, s2)
22 | fractal(cx-s2, cy+s2, s2)
23 | fractal(cx+s2, cy+s2, s2)
24 | }
25 | }
--------------------------------------------------------------------------------
/examples/canvas/fx_basic_shapes.own:
--------------------------------------------------------------------------------
1 | use canvasfx
2 |
3 | // https://docs.oracle.com/javafx/2/canvas/jfxpub-canvas.htm
4 |
5 | g = window("JavaFX Basic shapes", 300, 250)
6 | g.setFill(Color.GREEN)
7 | g.setStroke(Color.BLUE)
8 | g.setLineWidth(5)
9 | g.strokeLine(40, 10, 10, 40)
10 | g.fillOval(10, 60, 30, 30)
11 | g.strokeOval(60, 60, 30, 30)
12 | g.fillRoundRect(110, 60, 30, 30, 10, 10)
13 | g.strokeRoundRect(160, 60, 30, 30, 10, 10)
14 | g.fillArc(10, 110, 30, 30, 45, 240, ArcType.OPEN)
15 | g.fillArc(60, 110, 30, 30, 45, 240, ArcType.CHORD)
16 | g.fillArc(110, 110, 30, 30, 45, 240, ArcType.ROUND)
17 | g.strokeArc(10, 160, 30, 30, 45, 240, ArcType.OPEN)
18 | g.strokeArc(60, 160, 30, 30, 45, 240, ArcType.CHORD)
19 | g.strokeArc(110, 160, 30, 30, 45, 240, ArcType.ROUND)
20 | g.fillPolygon([10, 40, 10, 40], [210, 210, 240, 240], 4)
21 | g.strokePolygon([60, 90, 60, 90], [210, 210, 240, 240], 4)
22 | g.strokePolyline([110, 140, 110, 140], [210, 210, 240, 240], 4)
23 | repaint()
--------------------------------------------------------------------------------
/examples/canvas/fx_event_handlers.own:
--------------------------------------------------------------------------------
1 | use canvasfx, std
2 |
3 | w = 800 h = 600
4 | g = window("JavaFX Event handler example", w, h)
5 |
6 | addEventHandler(Events.MOUSE_MOVED, ::onMouseMoved)
7 | addEventHandler(Events.MOUSE_DRAGGED, ::onMouseMoved)
8 | addEventHandler(Events.KEY_PRESSED, def(e) {
9 | if (e.code == KeyCode.C) clearRect(0, 0, w, h)
10 | })
11 |
12 | def onMouseMoved(e) {
13 | g.setFill(Color.rgb(rand(255), rand(255), rand(255), rand()))
14 | m = 1 + e.isPrimaryButtonDown + e.isSecondaryButtonDown
15 | radius = m * rand(30, 50)
16 | g.fillOval(e.x - radius/2, e.y - radius/2, radius, radius)
17 | }
--------------------------------------------------------------------------------
/examples/canvas/fx_global_alpha.own:
--------------------------------------------------------------------------------
1 | use canvasfx
2 |
3 | steps = 20
4 | size = 25
5 | w = steps * (size * 1.25)
6 | h = size * 1.5
7 |
8 | step = 1.0 / steps
9 |
10 | g = window("JavaFX Global Alpha example", w, h)
11 |
12 | g.setFill(Color.RED)
13 | y = size * 0.25
14 | for a = 0, a <= 1.0, a += step {
15 | g.setGlobalAlpha(a)
16 | g.fillRect(a * w, y, size, size)
17 | }
--------------------------------------------------------------------------------
/examples/canvas/fx_image.own:
--------------------------------------------------------------------------------
1 | use canvasfx
2 |
3 | g = window("JavaFX Image demo", 400, 200)
4 | img = createImage("https://picsum.photos/400/200/")
5 | g.drawImage(img, 0, 0)
6 | repaint()
--------------------------------------------------------------------------------
/examples/canvas/fx_image_negate.own:
--------------------------------------------------------------------------------
1 | use std, canvasfx
2 |
3 | graphics = window("JavaFX Image negation demo", 400, 400)
4 | imgSource = createImage("https://picsum.photos/400/200/")
5 | pixels = imgSource.getPixels()
6 | size = length(pixels)
7 | for i = 0, i < size, i++ {
8 | pixel = pixels[i]
9 | r = (pixel >> 16) & 0xFF
10 | g = (pixel >> 8) & 0xFF
11 | b = pixel & 0xFF
12 | r = 255 - r
13 | g = 255 - g
14 | b = 255 - b
15 | pixels[i] = 0xFF000000 | (r << 16) | (g << 8) | b
16 | }
17 | imgNegate = createImage(imgSource.width, imgSource.height, pixels)
18 |
19 | graphics.drawImage(imgSource, 0, 0)
20 | graphics.drawImage(imgNegate, 0, 200)
21 | repaint()
--------------------------------------------------------------------------------
/examples/canvas/fx_rotation.own:
--------------------------------------------------------------------------------
1 | use canvasfx, std
2 |
3 | // http://www.developer.com/java/data/using-graphics-in-javafx.html
4 |
5 | width = 800 height = 600
6 | g = window("JavaFX Rotation example", width, height)
7 |
8 | g.translate(width / 2, height / 2)
9 |
10 | def randomColor() = Color.rgb(rand(255), rand(255), rand(255), 0.9)
11 |
12 | for i = 0, i < 60, i++ {
13 | g.rotate(6.0)
14 | g.setFill(randomColor())
15 | g.fillOval(10, 60, 30, 30)
16 | g.setStroke(randomColor())
17 | g.strokeOval(60, 60, 30, 30)
18 | g.setFill(randomColor())
19 | g.fillRoundRect(110, 60, 30, 30, 10, 10)
20 | g.setFill(randomColor())
21 | g.fillPolygon([105, 117, 159, 123, 133, 105, 77, 87, 51, 93],
22 | [150, 186, 186, 204, 246, 222, 246, 204, 186, 186], 10)
23 | }
--------------------------------------------------------------------------------
/examples/console/colors.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | // header
4 | print " " * 4
5 | for b : range(9)
6 | print sprintf(" 4%dm ", b)
7 | println ""
8 |
9 | for f : range(30, 39) {
10 | for s : ["", "1;"] {
11 | print sprintf("%4sm", s+f)
12 | print sprintf(" \u001B[%sm%s\u001B[0m", s+f, "gYw ")
13 | for b : range(8)
14 | print sprintf(" \u001B[4%s;%sm%s\u001B[0m", b, s+f, " gYw ")
15 | println ""
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/examples/database/hsqldb.own:
--------------------------------------------------------------------------------
1 | use std, jdbc
2 |
3 | connection = getConnection("jdbc:hsqldb:file:hsql.db", "", "", "org.hsqldb.jdbcDriver")
4 | statement = connection.createStatement()
5 | statement.executeUpdate("drop table if exists cities")
6 | statement.executeUpdate("CREATE TABLE cities (id IDENTITY, name VARCHAR(32))")
7 | statement.executeUpdate("INSERT INTO cities (name) VALUES('Киев')")
8 | statement.executeUpdate("INSERT INTO cities (name) VALUES('Минск')")
9 | statement.executeUpdate("INSERT INTO cities (name) VALUES('Москва')")
10 |
11 | rs = statement.executeQuery("SELECT id, name FROM cities")
12 | while(rs.next()) {
13 | // read the result set
14 | println "name = " + rs.getString("name")
15 | println "id = " + rs.getInt("id")
16 | }
17 | statement.execute("SHUTDOWN")
18 |
--------------------------------------------------------------------------------
/examples/database/sqlite.own:
--------------------------------------------------------------------------------
1 | use std, jdbc
2 |
3 | // Example from https://github.com/xerial/sqlite-jdbc
4 |
5 | connection = getConnection("jdbc:sqlite:sample.db")
6 | statement = connection.createStatement()
7 | statement.setQueryTimeout(30) // set timeout to 30 sec.
8 |
9 | statement.executeUpdate("drop table if exists person")
10 | statement.executeUpdate("create table person (id integer, name string)")
11 | statement.executeUpdate("insert into person values(1, 'leo')")
12 | statement.executeUpdate("insert into person values(2, 'yui')")
13 |
14 | rs = statement.executeQuery("select * from person")
15 | while(rs.next()) {
16 | // read the result set
17 | println "name = " + rs.getString("name")
18 | println "id = " + rs.getInt("id")
19 | }
20 |
--------------------------------------------------------------------------------
/examples/formats/json.own:
--------------------------------------------------------------------------------
1 | use json
2 |
3 | data = {
4 | "name": "Json Example",
5 | "version": 1,
6 | "arrayData": [
7 | 1, 2, 3, 4
8 | ],
9 | "objectData": {
10 | "key": "value",
11 | 10: "1000"
12 | }
13 | }
14 | println "Json encode"
15 | println "Minified: " + jsonencode(data)
16 | println "Pretty-print: " + jsonencode(data, 2)
17 |
--------------------------------------------------------------------------------
/examples/formats/zip.own:
--------------------------------------------------------------------------------
1 | use zip
2 |
3 | // println "Zip single file"
4 | // zip("absolute path to file", "example.zip")
5 |
6 | println "Zip files"
7 | zipFiles(["json.own", "yaml.own", "zip.own"], "example1.zip")
8 |
9 | println "Zip files"
10 | zipFiles({
11 | "json.own": "json.txt",
12 | "yaml.own": "yaml/yaml.own",
13 | "zip.own": "readme.md"}, "example2.zip")
14 |
15 | println "List zip entries"
16 | println listZipEntries("example2.zip").joinToString(", ")
17 |
--------------------------------------------------------------------------------
/examples/forms/basic.own:
--------------------------------------------------------------------------------
1 | use forms
2 |
3 | window = newWindow("Basic form example")
4 | window.add("Hello, world")
5 | window.pack()
6 | window.setVisible()
--------------------------------------------------------------------------------
/examples/forms/button.own:
--------------------------------------------------------------------------------
1 | use forms
2 |
3 | button = newButton("Click me")
4 | button.onClick(def() {
5 | println "Oh, you clicked me."
6 | })
7 |
8 | window = newWindow("Button example")
9 | window.add(button)
10 | window.pack()
11 | window.setVisible()
--------------------------------------------------------------------------------
/examples/forms/look_and_feel.own:
--------------------------------------------------------------------------------
1 | use java, forms
2 |
3 | UIManager = newClass("javax.swing.UIManager")
4 | // UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel")
5 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
6 |
7 | label = newLabel("Current value: 50")
8 | progressBar = newProgressBar()
9 | progressBar.setValue(50)
10 | progressBar.onChange(def() {
11 | label.setText("Current value: " + progressBar.getValue())
12 | })
13 | minusBtn = newButton("-1")
14 | minusBtn.onClick(def() = changeProgress(-1))
15 | plusBtn = newButton("+1")
16 | plusBtn.onClick(def() = changeProgress(1))
17 |
18 | def changeProgress(delta) {
19 | value = progressBar.getValue() + delta
20 | if (value > 100) value = 100
21 | else if (value < 0) value = 0
22 | progressBar.setValue(value)
23 | }
24 |
25 | window = newWindow("ProgressBar example")
26 | window.add(minusBtn, BorderLayout.WEST)
27 | window.add(progressBar, BorderLayout.CENTER)
28 | window.add(plusBtn, BorderLayout.EAST)
29 | window.add(label, BorderLayout.SOUTH)
30 | window.pack()
31 | window.setLocationByPlatform()
32 | window.setResizable(false)
33 | window.setVisible()
34 |
--------------------------------------------------------------------------------
/examples/forms/panel.own:
--------------------------------------------------------------------------------
1 | use forms
2 |
3 | // Create Panel with BoxLayout
4 | panel = newPanel()
5 | panel.setLayout(boxLayout(panel, BoxLayout.PAGE_AXIS))
6 | // String label (alias to JLabel)
7 | panel.add("String label")
8 |
9 | // Add label
10 | label = newLabel("Label")
11 | label.setHorizontalAlignment(SwingConstants.CENTER)
12 | panel.add(label)
13 |
14 | // Add text field
15 | textField = newTextField("Some text")
16 | textField.setColumns(20)
17 | panel.add(textField)
18 |
19 | // Add button
20 | button = newButton("Button")
21 | panel.add(button)
22 |
23 | // Add another button
24 | clearBtn = newButton("Clear panel")
25 | clearBtn.onClick(def() {
26 | panel.removeAll()
27 | panel.revalidate()
28 | panel.repaint()
29 | })
30 | panel.add(clearBtn)
31 |
32 | window = newWindow("Panel Example")
33 | window.setLocation(400, 200)
34 | window.add(panel)
35 | window.pack()
36 | window.setAlwaysOnTop()
37 | window.setVisible()
--------------------------------------------------------------------------------
/examples/forms/progressbar.own:
--------------------------------------------------------------------------------
1 | use forms
2 |
3 | label = newLabel("Current value: 50")
4 | progressBar = newProgressBar()
5 | progressBar.setValue(50)
6 | progressBar.onChange(def() {
7 | label.setText("Current value: " + progressBar.getValue())
8 | })
9 | minusBtn = newButton("-1")
10 | minusBtn.onClick(def() = changeProgress(-1))
11 | plusBtn = newButton("+1")
12 | plusBtn.onClick(def() = changeProgress(1))
13 |
14 | def changeProgress(delta) {
15 | value = progressBar.getValue() + delta
16 | if (value > 100) value = 100
17 | else if (value < 0) value = 0
18 | progressBar.setValue(value)
19 | }
20 |
21 | window = newWindow("ProgressBar example")
22 | window.add(minusBtn, BorderLayout.WEST)
23 | window.add(progressBar, BorderLayout.CENTER)
24 | window.add(plusBtn, BorderLayout.EAST)
25 | window.add(label, BorderLayout.SOUTH)
26 | window.pack()
27 | window.setLocationByPlatform()
28 | window.setResizable(false)
29 | window.setVisible()
--------------------------------------------------------------------------------
/examples/forms/samobot_chat.own:
--------------------------------------------------------------------------------
1 | use std, http, forms
2 |
3 | chatHistory = newLabel("Чат с самоботом
")
4 | messageField = newTextField()
5 | sendButton = newButton("Отправить")
6 |
7 | messageField.onAction(::onSend)
8 | sendButton.onClick(::onSend)
9 | def onSend() {
10 | text = messageField.getText()
11 | if (length(text) == 0) return 0
12 | messageField.setText("")
13 | chatHistory.setText(chatHistory.getText() + "
вы > " + text)
14 | thread(::http, "https://annimon.com/json/bot.php", "POST", {"text": text}, def(answer) {
15 | chatHistory.setText(chatHistory.getText() + "
бот > " + answer)
16 | })
17 | }
18 |
19 | messagePanel = newPanel()
20 | messagePanel.setLayout(boxLayout(messagePanel, BoxLayout.LINE_AXIS))
21 | messagePanel.add(messageField)
22 | messagePanel.add(sendButton)
23 |
24 | mainPanel = newPanel(borderLayout(10, 10))
25 | mainPanel.setPreferredSize(400, 250)
26 | mainPanel.add(chatHistory, BorderLayout.CENTER)
27 | mainPanel.add(messagePanel, BorderLayout.SOUTH)
28 |
29 |
30 | window = newWindow("Чат с самоботом")
31 | window.setMinimumSize(200, 220)
32 | window.setLocationByPlatform()
33 | window.add(mainPanel)
34 | window.pack()
35 | window.setVisible()
36 |
--------------------------------------------------------------------------------
/examples/forms/textarea.own:
--------------------------------------------------------------------------------
1 | use std, forms, functional
2 |
3 | text = map(range(1, 16), def(x) = "line " + x).joinToString("\n")
4 | label = newLabel()
5 | textArea = newTextArea(text)
6 | textArea.addCaretListener(def(event) = updateInfo())
7 | textArea.addDocumentListener(def(type, event) = updateInfo())
8 | updateInfo()
9 |
10 | def updateInfo() {
11 | text = "Text length: " + textArea.getText().length
12 | text += ", lines: " + textArea.getLineCount()
13 | selectedText = default(textArea.getSelectedText(), "")
14 | if (!selectedText.isEmpty()) {
15 | text += ", selected: " + selectedText.length
16 | }
17 | label.setText(text)
18 | }
19 |
20 | window = newWindow("JTextArea example")
21 | window.add(newScrollPane(textArea), BorderLayout.CENTER)
22 | window.add(label, BorderLayout.SOUTH)
23 | window.setSize(300, 200)
24 | window.setLocationByPlatform()
25 | window.setVisible()
--------------------------------------------------------------------------------
/examples/forms/textfield.own:
--------------------------------------------------------------------------------
1 | use std, forms
2 |
3 | textField = newTextField("Some text")
4 |
5 | button = newButton("Click me")
6 | button.onClick(def() {
7 | println "TextField text: " + textField.getText()
8 | textField.setText(textField.getText() + " Let's add new line")
9 | })
10 |
11 | window = newWindow("Text field example")
12 | window.add(textField)
13 | window.add(button, BorderLayout.SOUTH)
14 | window.pack()
15 | window.setLocationByPlatform()
16 | window.setVisible()
17 |
18 | textField.onAction(def() = echo("I am a TextField"))
19 | textField.addKeyListener(def(type, event) {
20 | println sprintf("%s %d %s",
21 | type, event.keyCode, toChar(event.keyChar))
22 | })
--------------------------------------------------------------------------------
/examples/forms/windowlistener.own:
--------------------------------------------------------------------------------
1 | use forms
2 |
3 | textArea = newTextArea("Window logs:")
4 |
5 | window = newWindow("Window listener example")
6 | window.addWindowListener(def(type, event) {
7 | textArea.append("\n" + type + ", id: " + match event.id {
8 | case WINDOW_OPENED: "WINDOW_OPENED"
9 | case WINDOW_CLOSING: "WINDOW_CLOSING"
10 | case WINDOW_CLOSED: "WINDOW_CLOSED"
11 | case WINDOW_ICONIFIED: "WINDOW_ICONIFIED"
12 | case WINDOW_DEICONIFIED: "WINDOW_DEICONIFIED"
13 | case WINDOW_ACTIVATED: "WINDOW_ACTIVATED"
14 | case WINDOW_DEACTIVATED: "WINDOW_DEACTIVATED"
15 | case WINDOW_GAINED_FOCUS: "WINDOW_GAINED_FOCUS"
16 | case WINDOW_LOST_FOCUS: "WINDOW_LOST_FOCUS"
17 | case WINDOW_STATE_CHANGED: "WINDOW_STATE_CHANGED"
18 | case _: "unknown type"
19 | })
20 | })
21 | window.add(newScrollPane(textArea))
22 | window.setSize(300, 200)
23 | window.setLocationByPlatform()
24 | window.setVisible()
--------------------------------------------------------------------------------
/examples/functions/basics.own:
--------------------------------------------------------------------------------
1 | use std, math, functional
2 |
3 | add = def(a,b) = a + b
4 | sub = def(a,b) = a - b
5 | mul = def(a,b) = a * b
6 | div = def(a,b) = a / b
7 | cube = def(x) = x * mul(x, x)
8 | println mul(8, 5)
9 | println cube(2)
10 |
11 | functions = [add, sub, mul, div]
12 | for f : functions {
13 | println f
14 | println f(6, 3)
15 | }
16 |
17 |
18 | map = {"+" : add, "-" : sub, "*" : mul, "/" : div}
19 | map["%"] = def(x,y) = x % y
20 | map["pow"] = def(x,y) = pow(x, y)
21 | foreach(map, def(op, func) = echo (4, op, 5, "=", func(4,5)))
--------------------------------------------------------------------------------
/examples/functions/calculator.own:
--------------------------------------------------------------------------------
1 | // Simple parser example
2 | use std, types
3 |
4 | operations = {
5 | "+" : def(a,b) = a+b,
6 | "-" : def(a,b) = a-b,
7 | "*" : def(a,b) = a*b,
8 | "/" : def(a,b) = a/b,
9 | "%" : def(a,b) = a%b,
10 | ">" : def(a,b) = a>b,
11 | "<" : def(a,b) = a4")
46 |
--------------------------------------------------------------------------------
/examples/functions/chain.own:
--------------------------------------------------------------------------------
1 | use std, functional
2 |
3 | data = [1,2,3,4,5,6,7,8,9]
4 | chain(data,
5 | ::filter, def(x) = x % 2 == 0,
6 | ::map, def(x) = [x, x * x, x * x * x],
7 | ::sortby, def(x) = -x[2],
8 | ::foreach, ::echo
9 | )
10 |
11 |
--------------------------------------------------------------------------------
/examples/functions/default_arguments.own:
--------------------------------------------------------------------------------
1 | def funcWithOptionalArgs(str, count = 5, prefix = "<", suffix = ">") = prefix + (str * count) + suffix
2 |
3 | println funcWithOptionalArgs("*")
4 | println funcWithOptionalArgs("+", 2)
5 | println funcWithOptionalArgs("*", 10, "
2 |
3 |
4 | Notes
5 |
6 |
7 |
8 |
9 |
Notes
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | -
20 |
Note 1
21 | Content
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/server/notes_public/notes.js:
--------------------------------------------------------------------------------
1 | const elNotes = document.querySelector('#notes');
2 | const elNoteTemplate = document.querySelector('templates ul[name="note"] li');
3 |
4 | function renderNote(note) {
5 | const el = elNoteTemplate.cloneNode(true);
6 | el.querySelector('h4').innerText = 'Note #' + note.id;
7 | el.querySelector('p').innerText = note.content;
8 | return el;
9 | }
10 |
11 | async function addNote() {
12 | const inpEl = document.querySelector('.new-note input');
13 | const content = inpEl.value;
14 | const resp = await fetch('/notes/', {
15 | method: "POST",
16 | body: content
17 | });
18 | const note = await resp.json();
19 | inpEl.value = '';
20 | console.log(note);
21 | elNotes.prepend(renderNote(note));
22 | }
23 |
24 | async function getNotes() {
25 | const resp = await fetch("/notes");
26 | const notes = await resp.json();
27 | elNotes.innerHTML = '';
28 | for (const note of notes) {
29 | elNotes.prepend(renderNote(note));
30 | }
31 | }
32 |
33 | getNotes();
--------------------------------------------------------------------------------
/examples/server/notes_public/styles.css:
--------------------------------------------------------------------------------
1 | templates {
2 | display: none;
3 | }
4 |
5 | #notes {
6 | list-style-type: none;
7 | padding: 0;
8 | }
9 | .note {
10 | margin: 0;
11 | padding: 0rem 0.3rem;
12 | }
13 | .note h4 {
14 | margin: 0;
15 | }
16 | .note p {
17 | color: #333;
18 | margin-top: 0;
19 | }
20 |
21 | .new-note {
22 | margin-bottom: 2rem;
23 | }
24 | .new-note input {
25 | width: 15rem;
26 | padding: 0.3rem;
27 | }
28 | .new-note button {
29 | padding: 0.3rem 1rem;
30 | background-color: #4caf50;
31 | color: #fff;
32 | border: none;
33 | cursor: pointer;
34 | font-size: 1rem;
35 | }
--------------------------------------------------------------------------------
/examples/server/server_spa_simple.own:
--------------------------------------------------------------------------------
1 | use std, jdbc, server
2 |
3 | // curl -X POST http://localhost:8084/notes/ -d "New note 2"
4 |
5 | notes = []
6 | createNote("This is your first note.")
7 |
8 | def createNote(content) {
9 | note = {"id": notes.length + 1, "content": content};
10 | notes += note
11 | return note
12 | }
13 |
14 | newServer({"externalDirs": ["notes_public"]})
15 | .get("/notes", def(ctx) = ctx.json(notes))
16 | .post("/notes", def(ctx) {
17 | ctx.status(201)
18 | ctx.json( createNote(ctx.body()) )
19 | })
20 | .start(8084)
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aNNiMON/Own-Programming-Language-Tutorial/f9c2bff15962b60ddc2d5b94a7f35d18e9b06900/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Aug 12 23:03:44 EEST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/modules/canvasfx/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'org.openjfx.javafxplugin' version "0.1.0"
4 | id 'com.github.johnrengelman.shadow' version '8.1.1'
5 | }
6 |
7 | group = 'com.annimon.module'
8 | version = '1.1.0'
9 |
10 | javafx {
11 | version = "21"
12 | modules = [ 'javafx.controls', 'javafx.swing' ]
13 | }
14 |
15 | dependencies {
16 | compileOnlyApi project(":ownlang-core")
17 |
18 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
19 | testImplementation 'org.junit.jupiter:junit-jupiter'
20 | }
21 |
22 | test {
23 | useJUnitPlatform()
24 | }
--------------------------------------------------------------------------------
/modules/jdbc/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'com.github.johnrengelman.shadow' version '8.1.1'
4 | }
5 |
6 | group = 'com.annimon.module'
7 | version = '1.0.0'
8 |
9 | dependencies {
10 | compileOnlyApi project(":ownlang-core")
11 |
12 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
13 | testImplementation 'org.junit.jupiter:junit-jupiter'
14 | }
15 |
16 | test {
17 | useJUnitPlatform()
18 | }
--------------------------------------------------------------------------------
/modules/main/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | }
4 |
5 | group = 'com.annimon.module'
6 | version = versions.project
7 |
8 | dependencies {
9 | compileOnlyApi project(":ownlang-core")
10 |
11 | implementation "com.squareup.okhttp3:okhttp:${versions.okhttp}"
12 | implementation "org.json:json:${versions.json}"
13 | implementation "org.yaml:snakeyaml:${versions.snakeyaml}"
14 |
15 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
16 | testImplementation 'org.junit.jupiter:junit-jupiter'
17 | }
18 |
19 | test {
20 | useJUnitPlatform()
21 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/forms/JButtonValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.forms;
2 |
3 | import javax.swing.JButton;
4 |
5 | public class JButtonValue extends AbstractButtonValue {
6 |
7 | final JButton jButton;
8 |
9 | public JButtonValue(JButton jButton) {
10 | super(0, jButton);
11 | this.jButton = jButton;
12 | init();
13 | }
14 |
15 | private void init() {
16 | }
17 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/forms/JFrameValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.forms;
2 |
3 | import static com.annimon.ownlang.lib.Converters.*;
4 | import javax.swing.JFrame;
5 |
6 | public class JFrameValue extends WindowValue {
7 |
8 | final JFrame frame;
9 |
10 | public JFrameValue(JFrame frame) {
11 | super(9, frame);
12 | this.frame = frame;
13 | init();
14 | }
15 |
16 | private void init() {
17 | set("getTitle", voidToString(frame::getTitle));
18 | set("getResizable", voidToBoolean(frame::isResizable));
19 | set("getDefaultCloseOperation", voidToInt(frame::getDefaultCloseOperation));
20 | set("setDefaultCloseOperation", intToVoid(frame::setDefaultCloseOperation));
21 | set("setResizable", booleanOptToVoid(frame::setResizable));
22 | set("setTitle", stringToVoid(frame::setTitle));
23 | }
24 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/forms/JPanelValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.forms;
2 |
3 | import javax.swing.JPanel;
4 |
5 | public class JPanelValue extends JComponentValue {
6 |
7 | final JPanel panel;
8 |
9 | public JPanelValue(JPanel panel) {
10 | super(0, panel);
11 | this.panel = panel;
12 | init();
13 | }
14 |
15 | private void init() {
16 | }
17 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/forms/LayoutManagerValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.forms;
2 |
3 | import com.annimon.ownlang.lib.MapValue;
4 | import java.awt.LayoutManager;
5 |
6 | public class LayoutManagerValue extends MapValue {
7 |
8 | final LayoutManager layout;
9 |
10 | public LayoutManagerValue(LayoutManager layout) {
11 | super(0);
12 | this.layout = layout;
13 | }
14 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/functional/functional_chain.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.functional;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.Value;
6 | import com.annimon.ownlang.lib.ValueUtils;
7 |
8 | final class functional_chain implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.checkAtLeast(2, args.length);
13 |
14 | Value result = args[0];
15 | for (int i = 1; i < args.length; i += 2) {
16 | final Function function = ValueUtils.consumeFunction(args[i], i);
17 | result = function.execute(result, args[i+1]);
18 | }
19 | return result;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/functional/functional_combine.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.functional;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.Function;
6 | import com.annimon.ownlang.lib.FunctionValue;
7 | import com.annimon.ownlang.lib.Types;
8 | import com.annimon.ownlang.lib.Value;
9 |
10 | final class functional_combine implements Function {
11 |
12 | @Override
13 | public Value execute(Value[] args) {
14 | Arguments.checkAtLeast(1, args.length);
15 | Function result = null;
16 | for (Value arg : args) {
17 | if (arg.type() != Types.FUNCTION) {
18 | throw new TypeException(arg + " is not a function");
19 | }
20 | final Function current = result;
21 | final Function next = ((FunctionValue) arg).getValue();
22 | result = fArgs -> {
23 | if (current == null) return next.execute(fArgs);
24 | return next.execute(current.execute(fArgs));
25 | };
26 | }
27 |
28 | return new FunctionValue(result);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/functional/functional_filterNot.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.functional;
2 |
3 | import com.annimon.ownlang.lib.*;
4 |
5 | final class functional_filterNot implements Function {
6 |
7 | @Override
8 | public Value execute(Value[] args) {
9 | Arguments.check(2, args.length);
10 | final Value container = args[0];
11 | final Function predicate = ValueUtils.consumeFunction(args[1], 1);
12 | return functional_filter.filter(container, negate(predicate));
13 | }
14 |
15 | static Function negate(Function f) {
16 | return args -> NumberValue.fromBoolean(f.execute(args) == NumberValue.ZERO);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/functional/functional_sortBy.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.functional;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.ArrayValue;
6 | import com.annimon.ownlang.lib.Function;
7 | import com.annimon.ownlang.lib.Types;
8 | import com.annimon.ownlang.lib.Value;
9 | import com.annimon.ownlang.lib.ValueUtils;
10 | import java.util.Arrays;
11 | import java.util.Comparator;
12 |
13 | final class functional_sortBy implements Function {
14 |
15 | @Override
16 | public Value execute(Value[] args) {
17 | Arguments.check(2, args.length);
18 | if (args[0].type() != Types.ARRAY) {
19 | throw new TypeException("Array expected at first argument");
20 | }
21 |
22 | final Value[] elements = ((ArrayValue) args[0]).getCopyElements();
23 | final Function function = ValueUtils.consumeFunction(args[1], 1);
24 | Arrays.sort(elements, Comparator.comparing(function::execute));
25 | return new ArrayValue(elements);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/functional/functional_stream.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.functional;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.*;
5 |
6 | final class functional_stream implements Function {
7 |
8 | @Override
9 | public Value execute(Value[] args) {
10 | Arguments.checkAtLeast(1, args.length);
11 |
12 | final Value value = args[0];
13 | return switch (value.type()) {
14 | case Types.MAP -> new StreamValue(((MapValue) value).toPairs());
15 | case Types.ARRAY -> new StreamValue((ArrayValue) value);
16 | default -> throw new TypeException("Invalid argument. Array or map expected");
17 | };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/http/http.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.http;
2 |
3 | import com.annimon.ownlang.lib.Function;
4 | import com.annimon.ownlang.lib.Value;
5 | import com.annimon.ownlang.modules.Module;
6 | import java.util.Collections;
7 | import java.util.Map;
8 |
9 | /**
10 | *
11 | * @author aNNiMON
12 | */
13 | public final class http implements Module {
14 |
15 | @Override
16 | public Map constants() {
17 | return Collections.emptyMap();
18 | }
19 |
20 | @Override
21 | public Map functions() {
22 | final var httpFunctions = new HttpFunctions();
23 | return Map.of(
24 | "urlencode", new http_urlencode(),
25 | "http", httpFunctions::http,
26 | "httpSync", httpFunctions::httpSync,
27 | "download", new http_download()
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/http/http_download.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.http;
2 |
3 | import com.annimon.ownlang.lib.*;
4 | import java.io.IOException;
5 | import okhttp3.*;
6 |
7 | public final class http_download implements Function {
8 |
9 | private final OkHttpClient client = new OkHttpClient();
10 |
11 | @Override
12 | public Value execute(Value[] args) {
13 | Arguments.check(1, args.length);
14 | try {
15 | final Response response = client.newCall(
16 | new Request.Builder().url(args[0].asString()).build())
17 | .execute();
18 | return ArrayValue.of(response.body().bytes());
19 | } catch (IOException ex) {
20 | return new ArrayValue(0);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/http/http_urlencode.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.http;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 | import java.io.IOException;
8 | import java.net.URLEncoder;
9 |
10 | public final class http_urlencode implements Function {
11 |
12 | @Override
13 | public Value execute(Value[] args) {
14 | Arguments.checkOrOr(1, 2, args.length);
15 |
16 | String charset = "UTF-8";
17 | if (args.length >= 2) {
18 | charset = args[1].asString();
19 | }
20 |
21 | try {
22 | final String result = URLEncoder.encode(args[0].asString(), charset);
23 | return new StringValue(result);
24 | } catch (IOException ex) {
25 | return args[0];
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/json/json.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.json;
2 |
3 | import com.annimon.ownlang.lib.Function;
4 | import com.annimon.ownlang.lib.Value;
5 | import com.annimon.ownlang.modules.Module;
6 | import java.util.Collections;
7 | import java.util.Map;
8 |
9 | /**
10 | *
11 | * @author aNNiMON
12 | */
13 | public final class json implements Module {
14 |
15 | @Override
16 | public Map constants() {
17 | return Collections.emptyMap();
18 | }
19 |
20 | @Override
21 | public Map functions() {
22 | return Map.of(
23 | "jsonencode", new json_encode(),
24 | "jsondecode", new json_decode()
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/json/json_decode.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.json;
2 |
3 | import com.annimon.ownlang.exceptions.OwnLangRuntimeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.Function;
6 | import com.annimon.ownlang.lib.Value;
7 | import com.annimon.ownlang.lib.ValueUtils;
8 | import org.json.JSONException;
9 | import org.json.JSONTokener;
10 |
11 | public final class json_decode implements Function {
12 |
13 | @Override
14 | public Value execute(Value[] args) {
15 | Arguments.check(1, args.length);
16 | try {
17 | final String jsonRaw = args[0].asString();
18 | final Object root = new JSONTokener(jsonRaw).nextValue();
19 | return ValueUtils.toValue(root);
20 | } catch (JSONException ex) {
21 | throw new OwnLangRuntimeException("Error while parsing json", ex);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/okhttp/MultipartBodyValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.okhttp;
2 |
3 | import com.annimon.ownlang.lib.Converters;
4 | import okhttp3.MultipartBody;
5 |
6 | public class MultipartBodyValue extends RequestBodyValue {
7 |
8 | private final MultipartBody multipartBody;
9 |
10 | public MultipartBodyValue(MultipartBody multipartBody) {
11 | super(multipartBody, 5);
12 | this.multipartBody = multipartBody;
13 | init();
14 | }
15 |
16 | public MultipartBody getMultipartBody() {
17 | return multipartBody;
18 | }
19 |
20 | private void init() {
21 | set("boundary", Converters.voidToString(multipartBody::boundary));
22 | set("size", Converters.voidToInt(multipartBody::size));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/robot/robot_fromclipboard.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.robot;
2 |
3 | import com.annimon.ownlang.lib.Function;
4 | import com.annimon.ownlang.lib.StringValue;
5 | import com.annimon.ownlang.lib.Value;
6 | import java.awt.Toolkit;
7 | import java.awt.datatransfer.DataFlavor;
8 |
9 | public final class robot_fromclipboard implements Function {
10 |
11 | @Override
12 | public Value execute(Value[] args) {
13 | try {
14 | Object data = Toolkit.getDefaultToolkit().getSystemClipboard()
15 | .getData(DataFlavor.stringFlavor);
16 | return new StringValue(data.toString());
17 | } catch (Exception ex) {
18 | return StringValue.EMPTY;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/robot/robot_toclipboard.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.robot;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 | import java.awt.Toolkit;
8 | import java.awt.datatransfer.StringSelection;
9 |
10 | public final class robot_toclipboard implements Function {
11 |
12 | @Override
13 | public Value execute(Value[] args) {
14 | Arguments.check(1, args.length);
15 | Toolkit.getDefaultToolkit().getSystemClipboard()
16 | .setContents(new StringSelection(args[0].asString()), null);
17 | return NumberValue.ZERO;
18 | }
19 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/NumberFunctions.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.NumberValue;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Types;
7 | import com.annimon.ownlang.lib.Value;
8 |
9 | final class NumberFunctions {
10 |
11 | private NumberFunctions() { }
12 |
13 | static Value toHexString(Value[] args) {
14 | Arguments.check(1, args.length);
15 | long value;
16 | if (args[0].type() == Types.NUMBER) {
17 | value = ((NumberValue) args[0]).asLong();
18 | } else {
19 | value = (long) args[0].asNumber();
20 | }
21 | return new StringValue(Long.toHexString(value));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_arrayKeyExists.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.Function;
6 | import com.annimon.ownlang.lib.MapValue;
7 | import com.annimon.ownlang.lib.NumberValue;
8 | import com.annimon.ownlang.lib.Types;
9 | import com.annimon.ownlang.lib.Value;
10 |
11 | final class std_arrayKeyExists implements Function {
12 |
13 | @Override
14 | public Value execute(Value[] args) {
15 | Arguments.check(2, args.length);
16 | if (args[1].type() != Types.MAP) {
17 | throw new TypeException("Map expected in second argument");
18 | }
19 | final MapValue map = ((MapValue) args[1]);
20 | return NumberValue.fromBoolean(map.containsKey(args[0]));
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_arrayKeys.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.ArrayValue;
6 | import com.annimon.ownlang.lib.Function;
7 | import com.annimon.ownlang.lib.MapValue;
8 | import com.annimon.ownlang.lib.Types;
9 | import com.annimon.ownlang.lib.Value;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | final class std_arrayKeys implements Function {
15 |
16 | @Override
17 | public Value execute(Value[] args) {
18 | Arguments.check(1, args.length);
19 | if (args[0].type() != Types.MAP) {
20 | throw new TypeException("Map expected in first argument");
21 | }
22 | final MapValue map = ((MapValue) args[0]);
23 | final List keys = new ArrayList<>(map.size());
24 | for (Map.Entry entry : map) {
25 | keys.add(entry.getKey());
26 | }
27 | return new ArrayValue(keys);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_arrayValues.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.exceptions.TypeException;
4 | import com.annimon.ownlang.lib.Arguments;
5 | import com.annimon.ownlang.lib.ArrayValue;
6 | import com.annimon.ownlang.lib.Function;
7 | import com.annimon.ownlang.lib.MapValue;
8 | import com.annimon.ownlang.lib.Types;
9 | import com.annimon.ownlang.lib.Value;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | final class std_arrayValues implements Function {
15 |
16 | @Override
17 | public Value execute(Value[] args) {
18 | Arguments.check(1, args.length);
19 | if (args[0].type() != Types.MAP) {
20 | throw new TypeException("Map expected in first argument");
21 | }
22 | final MapValue map = ((MapValue) args[0]);
23 | final List values = new ArrayList<>(map.size());
24 | for (Map.Entry entry : map) {
25 | values.add(entry.getValue());
26 | }
27 | return new ArrayValue(values);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_charat.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_charat implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(2, args.length);
13 |
14 | final String input = args[0].asString();
15 | final int index = args[1].asInt();
16 |
17 | return NumberValue.of((short)input.charAt(index));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_default.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.*;
4 |
5 | final class std_default implements Function {
6 |
7 | @Override
8 | public Value execute(Value[] args) {
9 | Arguments.check(2, args.length);
10 | if (isEmpty(args[0])) {
11 | return args[1];
12 | }
13 | return args[0];
14 | }
15 |
16 | private boolean isEmpty(Value value) {
17 | if (value == null || value.raw() == null) {
18 | return true;
19 | }
20 | return switch (value.type()) {
21 | case Types.NUMBER -> (value.asInt() == 0);
22 | case Types.STRING -> (value.asString().isEmpty());
23 | case Types.ARRAY -> ((ArrayValue) value).size() == 0;
24 | case Types.MAP -> ((MapValue) value).size() == 0;
25 | case Types.CLASS -> ((ClassInstance) value).getThisMap().size() == 0;
26 | default -> false;
27 | };
28 | }
29 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_echo.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_echo implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | final StringBuilder sb = new StringBuilder();
13 | for (Value arg : args) {
14 | sb.append(arg.asString());
15 | sb.append(' ');
16 | }
17 | Console.println(sb.toString());
18 | return NumberValue.ZERO;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_indexof.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_indexof implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.checkOrOr(2, 3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String what = args[1].asString();
16 | final int index = (args.length == 3) ? args[2].asInt() : 0;
17 |
18 | return NumberValue.of(input.indexOf(what, index));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_lastindexof.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_lastindexof implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.checkOrOr(2, 3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String what = args[1].asString();
16 | if (args.length == 2) {
17 | return NumberValue.of(input.lastIndexOf(what));
18 | }
19 | final int index = args[2].asInt();
20 | return NumberValue.of(input.lastIndexOf(what, index));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_length.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.*;
4 |
5 | final class std_length implements Function {
6 |
7 | @Override
8 | public Value execute(Value[] args) {
9 | Arguments.check(1, args.length);
10 |
11 | final Value value = args[0];
12 | final int length = switch (value.type()) {
13 | case Types.ARRAY -> ((ArrayValue) value).size();
14 | case Types.MAP -> ((MapValue) value).size();
15 | case Types.CLASS -> ((ClassInstance) value).getThisMap().size();
16 | case Types.STRING -> ((StringValue) value).length();
17 | case Types.FUNCTION -> {
18 | final Function func = ((FunctionValue) value).getValue();
19 | yield func.getArgsCount();
20 | }
21 | default -> 0;
22 | };
23 | return NumberValue.of(length);
24 | }
25 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_newarray.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.ArrayValue;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_newarray implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | return createArray(args, 0);
13 | }
14 |
15 | private ArrayValue createArray(Value[] args, int index) {
16 | final int size = args[index].asInt();
17 | final int last = args.length - 1;
18 | ArrayValue array = new ArrayValue(size);
19 | if (index == last) {
20 | for (int i = 0; i < size; i++) {
21 | array.set(i, NumberValue.ZERO);
22 | }
23 | } else if (index < last) {
24 | for (int i = 0; i < size; i++) {
25 | array.set(i, createArray(args, index + 1));
26 | }
27 | }
28 | return array;
29 | }
30 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_readln.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Function;
4 | import com.annimon.ownlang.lib.StringValue;
5 | import com.annimon.ownlang.lib.Value;
6 | import java.util.Scanner;
7 |
8 | final class std_readln implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | try (Scanner sc = new Scanner(System.in)) {
13 | return new StringValue(sc.nextLine());
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_replace.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_replace implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String target = args[1].asString();
16 | final String replacement = args[2].asString();
17 |
18 | return new StringValue(input.replace(target, replacement));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_replaceall.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_replaceall implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String regex = args[1].asString();
16 | final String replacement = args[2].asString();
17 |
18 | return new StringValue(input.replaceAll(regex, replacement));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_replacefirst.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_replacefirst implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String regex = args[1].asString();
16 | final String replacement = args[2].asString();
17 |
18 | return new StringValue(input.replaceFirst(regex, replacement));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_sleep.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.NumberValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_sleep implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(1, args.length);
13 |
14 | try {
15 | Thread.sleep((long) args[0].asNumber());
16 | } catch (InterruptedException ex) {
17 | Thread.currentThread().interrupt();
18 | }
19 | return NumberValue.ZERO;
20 | }
21 | }
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_split.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.ArrayValue;
5 | import com.annimon.ownlang.lib.Function;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_split implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.checkOrOr(2, 3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final String regex = args[1].asString();
16 | final int limit = (args.length == 3) ? args[2].asInt() : 0;
17 |
18 | final String[] parts = input.split(regex, limit);
19 | return ArrayValue.of(parts);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_sprintf.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Types;
7 | import com.annimon.ownlang.lib.Value;
8 |
9 | final class std_sprintf implements Function {
10 |
11 | @Override
12 | public Value execute(Value[] args) {
13 | Arguments.checkAtLeast(1, args.length);
14 |
15 | final String format = args[0].asString();
16 | final Object[] values = new Object[args.length - 1];
17 | for (int i = 1; i < args.length; i++) {
18 | values[i - 1] = (args[i].type() == Types.NUMBER)
19 | ? args[i].raw()
20 | : args[i].asString();
21 | }
22 | return new StringValue(String.format(format, values));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_substring.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_substring implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.checkOrOr(2, 3, args.length);
13 |
14 | final String input = args[0].asString();
15 | final int startIndex = args[1].asInt();
16 |
17 | String result;
18 | if (args.length == 2) {
19 | result = input.substring(startIndex);
20 | } else {
21 | final int endIndex = args[2].asInt();
22 | result = input.substring(startIndex, endIndex);
23 | }
24 |
25 | return new StringValue(result);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_thread.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.lib.*;
5 |
6 | final class std_thread implements Function {
7 |
8 | @Override
9 | public Value execute(Value[] args) {
10 | Arguments.checkAtLeast(1, args.length);
11 |
12 | Function body;
13 | if (args[0].type() == Types.FUNCTION) {
14 | body = ((FunctionValue) args[0]).getValue();
15 | } else {
16 | body = ScopeHandler.getFunction(args[0].asString());
17 | }
18 |
19 | // Shift arguments
20 | final Value[] params = new Value[args.length - 1];
21 | if (params.length > 0) {
22 | System.arraycopy(args, 1, params, 0, params.length);
23 | }
24 |
25 | final Thread thread = new Thread(() -> body.execute(params));
26 | thread.setUncaughtExceptionHandler(Console::handleException);
27 | thread.start();
28 | return NumberValue.ZERO;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_tochar.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_tochar implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(1, args.length);
13 | return new StringValue(String.valueOf((char) args[0].asInt()));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_tolowercase.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_tolowercase implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(1, args.length);
13 | return new StringValue(args[0].asString().toLowerCase());
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_touppercase.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_touppercase implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(1, args.length);
13 | return new StringValue(args[0].asString().toUpperCase());
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_trim.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.Arguments;
4 | import com.annimon.ownlang.lib.Function;
5 | import com.annimon.ownlang.lib.StringValue;
6 | import com.annimon.ownlang.lib.Value;
7 |
8 | final class std_trim implements Function {
9 |
10 | @Override
11 | public Value execute(Value[] args) {
12 | Arguments.check(1, args.length);
13 | return new StringValue(args[0].asString().trim());
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/std/std_try.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.std;
2 |
3 | import com.annimon.ownlang.lib.*;
4 |
5 | final class std_try implements Function {
6 |
7 | @Override
8 | public Value execute(Value[] args) {
9 | Arguments.checkOrOr(1, 2, args.length);
10 | try {
11 | return ValueUtils.consumeFunction(args[0], 0).execute();
12 | } catch (Exception ex) {
13 | if (args.length == 2) {
14 | switch (args[1].type()) {
15 | case Types.FUNCTION:
16 | final String message = ex.getMessage();
17 | final Function catchFunction = ((FunctionValue) args[1]).getValue();
18 | return catchFunction.execute(
19 | new StringValue(ex.getClass().getName()),
20 | new StringValue(message == null ? "" : message));
21 | default:
22 | return args[1];
23 | }
24 | }
25 | return NumberValue.MINUS_ONE;
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/modules/main/src/main/java/com/annimon/ownlang/modules/yaml/yaml.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules.yaml;
2 |
3 | import com.annimon.ownlang.lib.*;
4 | import com.annimon.ownlang.modules.Module;
5 | import java.util.Collections;
6 | import java.util.Map;
7 |
8 | /**
9 | *
10 | * @author aNNiMON
11 | */
12 | public final class yaml implements Module {
13 |
14 | @Override
15 | public Map constants() {
16 | return Collections.emptyMap();
17 | }
18 |
19 | @Override
20 | public Map functions() {
21 | return Map.of(
22 | "yamlencode", new yaml_encode(),
23 | "yamldecode", new yaml_decode()
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/modules/server/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'com.github.johnrengelman.shadow' version '8.1.1'
4 | }
5 |
6 | group = 'com.annimon.module'
7 | version = '1.0.0'
8 |
9 | dependencies {
10 | compileOnlyApi project(":ownlang-core")
11 | implementation "io.javalin:javalin:${versions.javalin}"
12 | implementation "org.slf4j:slf4j-simple:${versions.slf4j}"
13 | implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}"
14 |
15 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
16 | testImplementation 'org.junit.jupiter:junit-jupiter'
17 | }
18 |
19 | test {
20 | useJUnitPlatform()
21 | }
--------------------------------------------------------------------------------
/modules/socket/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'com.github.johnrengelman.shadow' version '8.1.1'
4 | }
5 |
6 | group = 'com.annimon.module'
7 | version = '1.0.0'
8 |
9 | dependencies {
10 | compileOnlyApi project(":ownlang-core")
11 |
12 | implementation ("io.socket:socket.io-client:${versions.socket}") {
13 | exclude group: 'org.json', module: 'json'
14 | exclude group: 'com.squareup.okhttp3', module: 'okhttp'
15 | }
16 | compileOnly "com.squareup.okhttp3:okhttp:${versions.okhttp}"
17 | compileOnly "org.json:json:${versions.json}"
18 |
19 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
20 | testImplementation 'org.junit.jupiter:junit-jupiter'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | }
--------------------------------------------------------------------------------
/ownlang-core/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | }
4 |
5 | group = 'com.annimon'
6 | version = versions.project
7 |
8 | dependencies {
9 | implementation "org.json:json:${versions.json}"
10 |
11 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
12 | testImplementation 'org.junit.jupiter:junit-jupiter'
13 | }
14 |
15 | test {
16 | useJUnitPlatform()
17 | }
18 |
19 | ext.generatedJavaDir = "${project.buildDir}/gen/src/main/java"
20 | sourceSets.main.java.srcDirs += project.generatedJavaDir
21 |
22 | tasks.register('generateJavaSources') {
23 | doLast {
24 | def source = """
25 | package com.annimon.ownlang;
26 | class Gen {
27 | private Gen() {}
28 | public static final String BUILD_DATE = "${new Date().format('YYMMdd')}";
29 | }
30 | """.stripIndent()
31 | def genFile = new File("${project.generatedJavaDir}/com/annimon/ownlang/Gen.java")
32 | genFile.getParentFile().mkdirs()
33 | genFile.write(source)
34 | }
35 | }
36 | compileJava.dependsOn(generateJavaSources)
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/Shared.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang;
2 |
3 | public final class Shared {
4 | private static String[] ownlangArgs = new String[0];
5 |
6 | public static String[] getOwnlangArgs() {
7 | return ownlangArgs;
8 | }
9 |
10 | public static void setOwnlangArgs(String[] args) {
11 | ownlangArgs = args;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/Version.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang;
2 |
3 | public final class Version {
4 | public static final int VERSION_MAJOR = 2;
5 | public static final int VERSION_MINOR = 1;
6 | public static final int VERSION_PATCH = 0;
7 |
8 | public static final String VERSION = VERSION_MAJOR + "."
9 | + VERSION_MINOR + "." + VERSION_PATCH
10 | + "_" + Gen.BUILD_DATE;
11 | }
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/ArgumentsMismatchException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | public final class ArgumentsMismatchException extends OwnLangRuntimeException {
6 |
7 | public ArgumentsMismatchException() {
8 | }
9 |
10 | public ArgumentsMismatchException(String message) {
11 | super(message);
12 | }
13 |
14 | public ArgumentsMismatchException(String message, Range range) {
15 | super(message, range);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/OperationIsNotSupportedException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | public final class OperationIsNotSupportedException extends OwnLangRuntimeException {
4 |
5 | public OperationIsNotSupportedException(Object operation) {
6 | super("Operation " + operation + " is not supported");
7 | }
8 |
9 | public OperationIsNotSupportedException(Object operation, String message) {
10 | super("Operation " + operation + " is not supported " + message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/OwnLangRuntimeException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 | import com.annimon.ownlang.util.SourceLocatedError;
5 |
6 | /**
7 | * Base type for all runtime exceptions
8 | */
9 | public class OwnLangRuntimeException extends RuntimeException implements SourceLocatedError {
10 |
11 | private final Range range;
12 |
13 | public OwnLangRuntimeException() {
14 | super();
15 | this.range = null;
16 | }
17 |
18 | public OwnLangRuntimeException(Exception ex) {
19 | super(ex);
20 | this.range = null;
21 | }
22 |
23 | public OwnLangRuntimeException(String message) {
24 | this(message, (Range) null);
25 | }
26 |
27 | public OwnLangRuntimeException(String message, Range range) {
28 | super(message);
29 | this.range = range;
30 | }
31 |
32 | public OwnLangRuntimeException(String message, Throwable ex) {
33 | super(message, ex);
34 | this.range = null;
35 | }
36 |
37 | @Override
38 | public Range getRange() {
39 | return range;
40 | }
41 | }
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/PatternMatchingException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | public final class PatternMatchingException extends OwnLangRuntimeException {
4 |
5 | public PatternMatchingException() {
6 | }
7 |
8 | public PatternMatchingException(String message) {
9 | super(message);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/StoppedException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | public class StoppedException extends OwnLangRuntimeException {
4 |
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/TypeException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | public final class TypeException extends OwnLangRuntimeException {
6 |
7 | public TypeException(String message) {
8 | super(message);
9 | }
10 |
11 | public TypeException(String message, Range range) {
12 | super(message, range);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/UnknownClassException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | public final class UnknownClassException extends OwnLangRuntimeException {
6 |
7 | private final String className;
8 |
9 | public UnknownClassException(String name, Range range) {
10 | super("Unknown class " + name, range);
11 | this.className = name;
12 | }
13 |
14 | public String getClassName() {
15 | return className;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/UnknownFunctionException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | public final class UnknownFunctionException extends OwnLangRuntimeException {
6 |
7 | private final String functionName;
8 |
9 | public UnknownFunctionException(String name) {
10 | super("Unknown function " + name);
11 | this.functionName = name;
12 | }
13 |
14 | public UnknownFunctionException(String name, Range range) {
15 | super("Unknown function " + name, range);
16 | this.functionName = name;
17 | }
18 |
19 | public String getFunctionName() {
20 | return functionName;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/UnknownPropertyException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | public final class UnknownPropertyException extends OwnLangRuntimeException {
4 |
5 | private final String propertyName;
6 |
7 | public UnknownPropertyException(String name) {
8 | super("Unknown property " + name);
9 | this.propertyName = name;
10 | }
11 |
12 | public String getPropertyName() {
13 | return propertyName;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/VariableDoesNotExistsException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | public final class VariableDoesNotExistsException extends OwnLangRuntimeException {
6 |
7 | private final String variable;
8 |
9 | public VariableDoesNotExistsException(String variable, Range range) {
10 | super("Variable " + variable + " does not exists", range);
11 | this.variable = variable;
12 | }
13 |
14 | public String getVariable() {
15 | return variable;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/AutoCloseableScope.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | public final class AutoCloseableScope implements AutoCloseable {
4 | @Override
5 | public void close() {
6 | ScopeHandler.pop();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | import java.util.List;
4 |
5 | public record ClassDeclaration(
6 | String name,
7 | List classFields,
8 | List classMethods
9 | ) implements Instantiable {
10 |
11 | /**
12 | * Create an instance and put evaluated fields with method declarations
13 | * @return new {@link ClassInstance}
14 | */
15 | public ClassInstance newInstance(Value[] args) {
16 | final var instance = new ClassInstance(name);
17 | for (ClassField f : classFields) {
18 | instance.addField(f);
19 | }
20 | for (ClassMethod m : classMethods) {
21 | instance.addMethod(m);
22 | }
23 | return instance.callConstructor(args);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassField.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | public record ClassField(
4 | String name,
5 | EvaluableValue evaluableValue
6 | ) {
7 | }
8 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/EvaluableValue.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | public interface EvaluableValue {
4 |
5 | Value eval();
6 | }
7 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Function.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | /**
4 | *
5 | * @author aNNiMON
6 | */
7 | public interface Function {
8 |
9 | Value execute(Value... args);
10 |
11 | default int getArgsCount() {
12 | return 0;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Functions.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | /**
4 | *
5 | * @author aNNiMON
6 | */
7 | public final class Functions {
8 | private Functions() { }
9 |
10 | /**
11 | * @deprecated This function remains for backward compatibility with old separate modules
12 | * Use {@link ScopeHandler#setFunction(String, Function)}
13 | */
14 | @Deprecated
15 | public static void set(String key, Function function) {
16 | ScopeHandler.setFunction(key, function);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Instantiable.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | /**
4 | * Interface for values that supports creating instances with `new` keyword.
5 | */
6 | public interface Instantiable {
7 |
8 | Value newInstance(Value[] args);
9 | }
10 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/ModuleLoader.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | import com.annimon.ownlang.modules.Module;
4 |
5 | public final class ModuleLoader {
6 | private static final String PACKAGE = "com.annimon.ownlang.modules.%s.%s";
7 |
8 | private ModuleLoader() { }
9 |
10 | public static Module load(String name) {
11 | try {
12 | return (Module) Class.forName(String.format(PACKAGE, name, name))
13 | .getDeclaredConstructor()
14 | .newInstance();
15 | } catch (Exception ex) {
16 | throw new RuntimeException("Unable to load module " + name, ex);
17 | }
18 | }
19 |
20 | public static void loadAndUse(String name) {
21 | final var rootScope = ScopeHandler.rootScope();
22 | if (rootScope.isModuleLoaded(name)) return;
23 |
24 | final var module = load(name);
25 | rootScope.getConstants().putAll(module.constants());
26 | rootScope.getFunctions().putAll(module.functions());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Types.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | public final class Types {
4 |
5 | public static final int
6 | OBJECT = 0,
7 | NUMBER = 1,
8 | STRING = 2,
9 | ARRAY = 3,
10 | MAP = 4,
11 | FUNCTION = 5,
12 | CLASS = 6;
13 |
14 | private static final int FIRST = OBJECT;
15 | private static final int LAST = CLASS;
16 | private static final String[] NAMES = {
17 | "object", "number", "string", "array", "map", "function", "class"
18 | };
19 |
20 | public static String typeToString(int type) {
21 | if (FIRST <= type && type <= LAST) {
22 | return NAMES[type];
23 | }
24 | return "unknown (" + type + ")";
25 | }
26 |
27 | private Types() { }
28 | }
29 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Value.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | /**
4 | *
5 | * @author aNNiMON
6 | */
7 | public interface Value extends Comparable {
8 |
9 | Object raw();
10 |
11 | int asInt();
12 |
13 | double asNumber();
14 |
15 | String asString();
16 |
17 | int type();
18 |
19 | default Object asJavaObject() {
20 | return raw();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/lib/Variables.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.lib;
2 |
3 | /**
4 | *
5 | * @author aNNiMON
6 | */
7 | public final class Variables {
8 | private Variables() { }
9 |
10 | /**
11 | * @deprecated This function remains for backward compatibility with old separate modules
12 | * Use {@link ScopeHandler#setVariable(String, Value)}
13 | */
14 | @Deprecated
15 | public static void set(String name, Value value) {
16 | ScopeHandler.setVariable(name, value);
17 | }
18 |
19 | /**
20 | * @deprecated This function remains for backward compatibility with old separate modules
21 | * Use {@link ScopeHandler#setConstant(String, Value)}
22 | */
23 | @Deprecated
24 | public static void define(String name, Value value) {
25 | ScopeHandler.setConstant(name, value);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/modules/Module.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.modules;
2 |
3 | import com.annimon.ownlang.lib.Function;
4 | import com.annimon.ownlang.lib.Value;
5 | import java.util.Map;
6 |
7 | /**
8 | * Main interface for modules
9 | * @author aNNiMON
10 | */
11 | public interface Module {
12 |
13 | Map constants();
14 |
15 | Map functions();
16 | }
17 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/outputsettings/OutputSettings.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.outputsettings;
2 |
3 | import java.io.File;
4 |
5 | public sealed interface OutputSettings permits ConsoleOutputSettings, StringOutputSettings {
6 |
7 | String newline();
8 |
9 | void print(String value);
10 |
11 | void print(Object value);
12 |
13 | void println();
14 |
15 | void println(String value);
16 |
17 | void println(Object value);
18 |
19 | String getText();
20 |
21 | void error(Throwable throwable);
22 |
23 | void error(CharSequence value);
24 |
25 | File fileInstance(String path);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/stages/ScopedStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import java.util.function.Consumer;
4 |
5 | public class ScopedStage implements Stage {
6 |
7 | private final String stageName;
8 | private final Stage super I, ? extends R> stage;
9 | private final Consumer startStage;
10 | private final Consumer endStage;
11 |
12 | ScopedStage(String stageName, Stage super I, ? extends R> stage,
13 | Consumer startStage, Consumer endStage) {
14 | this.stageName = stageName;
15 | this.stage = stage;
16 | this.startStage = startStage;
17 | this.endStage = endStage;
18 | }
19 |
20 | @Override
21 | public R perform(StagesData stagesData, I input) {
22 | try {
23 | startStage.accept(stageName);
24 | return stage.perform(stagesData, input);
25 | } finally {
26 | endStage.accept(stageName);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/stages/ScopedStageFactory.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import java.util.function.Consumer;
4 |
5 | public final class ScopedStageFactory {
6 | private final Consumer startStage;
7 | private final Consumer endStage;
8 |
9 | public ScopedStageFactory(Consumer startStage, Consumer endStage) {
10 | this.startStage = startStage;
11 | this.endStage = endStage;
12 | }
13 |
14 | public ScopedStage create(String stageName, Stage super I, ? extends R> stage) {
15 | return new ScopedStage<>(stageName, stage, startStage, endStage);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/stages/Stage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | public interface Stage {
4 | R perform(StagesData stagesData, I input);
5 |
6 | default Stage then(Stage super R, ? extends NR> next) {
7 | return (scope, input) -> {
8 | R result = perform(scope, input);
9 | return next.perform(scope, result);
10 | };
11 | }
12 |
13 | default Stage thenConditional(boolean enabled, Stage super R, ? extends R> next) {
14 | return enabled ? then(next) : this;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/stages/StagesData.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import java.util.function.Supplier;
4 |
5 | public interface StagesData {
6 |
7 | T get(String tag);
8 |
9 | default T getOrDefault(String tag, T other) {
10 | T value = get(tag);
11 | return value != null ? value : other;
12 | }
13 |
14 | default T getOrDefault(String tag, Supplier extends T> otherSuppler) {
15 | T value = get(tag);
16 | return value != null ? value : otherSuppler.get();
17 | }
18 |
19 | void put(String tag, Object input);
20 | }
21 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/stages/StagesDataMap.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public class StagesDataMap implements StagesData {
7 | private final Map data = new HashMap<>();
8 |
9 | @SuppressWarnings("unchecked")
10 | @Override
11 | public T get(String tag) {
12 | return (T) data.get(tag);
13 | }
14 |
15 | @Override
16 | public void put(String tag, Object input) {
17 | data.put(tag, input);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/ErrorsStackTraceFormatterStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.stages.Stage;
5 | import com.annimon.ownlang.stages.StagesData;
6 |
7 | public class ErrorsStackTraceFormatterStage implements Stage, String> {
8 |
9 | @Override
10 | public String perform(StagesData stagesData, Iterable extends SourceLocatedError> input) {
11 | final var sb = new StringBuilder();
12 | for (SourceLocatedError error : input) {
13 | if (!error.hasStackTrace()) continue;
14 | for (StackTraceElement el : error.getStackTrace()) {
15 | sb.append("\t").append(el).append(Console.newline());
16 | }
17 | }
18 | return sb.toString();
19 | }
20 | }
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/ExceptionConverterStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | import com.annimon.ownlang.stages.Stage;
4 | import com.annimon.ownlang.stages.StagesData;
5 |
6 | public class ExceptionConverterStage implements Stage {
7 | @Override
8 | public SourceLocatedError perform(StagesData stagesData, Exception ex) {
9 | if (ex instanceof SourceLocatedError sle) return sle;
10 | return new SimpleError(ex.getMessage());
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/ExceptionStackTraceToStringStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | import com.annimon.ownlang.stages.Stage;
4 | import com.annimon.ownlang.stages.StagesData;
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.PrintStream;
7 | import java.nio.charset.StandardCharsets;
8 |
9 | public class ExceptionStackTraceToStringStage implements Stage {
10 | @Override
11 | public String perform(StagesData stagesData, Exception ex) {
12 | final var baos = new ByteArrayOutputStream();
13 | try (final PrintStream ps = new PrintStream(baos)) {
14 | for (StackTraceElement traceElement : ex.getStackTrace()) {
15 | ps.println("\tat " + traceElement);
16 | }
17 | }
18 | return baos.toString(StandardCharsets.UTF_8);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/Pos.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | public record Pos(int row, int col) {
4 | public static final Pos UNKNOWN = new Pos(-1, -1);
5 | public static final Pos ZERO = new Pos(0, 0);
6 |
7 | public Pos normalize() {
8 | return new Pos(Math.max(0, row - 1), Math.max(0, col - 1));
9 | }
10 |
11 | public String format() {
12 | return "[" + row + ":" + col + "]";
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/Range.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | import java.util.Objects;
4 |
5 | public record Range(Pos start, Pos end) {
6 | public static final Range ZERO = new Range(Pos.ZERO, Pos.ZERO);
7 |
8 | public Range normalize() {
9 | return new Range(start.normalize(), end.normalize());
10 | }
11 |
12 | public boolean isEqualPosition() {
13 | return Objects.equals(start, end);
14 | }
15 |
16 | public boolean isOnSameLine() {
17 | return start.row() == end.row();
18 | }
19 |
20 | public String format() {
21 | if (isEqualPosition())
22 | return start.format();
23 | else if (isOnSameLine()) {
24 | return "[%d:%d~%d]".formatted(start.row(), start.col(), end.col());
25 | } else {
26 | return start.format() + "..." + end.format();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/SimpleError.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | public record SimpleError(String message, Range range) implements SourceLocatedError {
4 | public SimpleError(String message) {
5 | this(message, null);
6 | }
7 |
8 | @Override
9 | public String getMessage() {
10 | return message;
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return message;
16 | }
17 |
18 | @Override
19 | public Range getRange() {
20 | return range;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocatedError.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | public interface SourceLocatedError extends SourceLocation {
4 |
5 | String getMessage();
6 |
7 | default StackTraceElement[] getStackTrace() {
8 | return new StackTraceElement[0];
9 | }
10 |
11 | default boolean hasStackTrace() {
12 | return !stackTraceIsEmpty();
13 | }
14 |
15 | private boolean stackTraceIsEmpty() {
16 | final var st = getStackTrace();
17 | return st == null || st.length == 0;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocation.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util;
2 |
3 | public interface SourceLocation {
4 |
5 | default Range getRange() {
6 | return null;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSource.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util.input;
2 |
3 | import java.io.IOException;
4 |
5 | public interface InputSource {
6 | String getPath();
7 |
8 | String load() throws IOException;
9 |
10 | default String getBasePath() {
11 | final String normalizedPath = getPath().replace("\\", "/");
12 | int i = normalizedPath.lastIndexOf("/");
13 | if (i == -1) return "";
14 | return normalizedPath.substring(0, i + 1);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSourceFile.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util.input;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 |
9 | public record InputSourceFile(String path) implements InputSource {
10 |
11 | @Override
12 | public String getPath() {
13 | return path;
14 | }
15 |
16 | @Override
17 | public String load() throws IOException {
18 | if (Files.isReadable(Path.of(path))) {
19 | try (InputStream is = new FileInputStream(path)) {
20 | return SourceLoaderStage.readStream(is);
21 | }
22 | }
23 | throw new IOException(path + " not found");
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "File " + path;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSourceProgram.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util.input;
2 |
3 | public record InputSourceProgram(String program) implements InputSource {
4 |
5 | @Override
6 | public String getPath() {
7 | return ".";
8 | }
9 |
10 | @Override
11 | public String load() {
12 | return program;
13 | }
14 |
15 | @Override
16 | public String toString() {
17 | return "Program";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ownlang-core/src/main/java/com/annimon/ownlang/util/input/InputSourceResource.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.util.input;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | public record InputSourceResource(String path) implements InputSource {
7 |
8 | @Override
9 | public String getPath() {
10 | return path;
11 | }
12 |
13 | @Override
14 | public String load() throws IOException {
15 | try (InputStream is = getClass().getResourceAsStream(path)) {
16 | if (is != null) {
17 | return SourceLoaderStage.readStream(is);
18 | }
19 | }
20 | throw new IOException(path + " not found");
21 | }
22 |
23 | @Override
24 | public String getBasePath() {
25 | return "resource:" + InputSource.super.getBasePath();
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return "Resource " + path;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ownlang-desktop/src/main/resources/scripts/listscripts.own:
--------------------------------------------------------------------------------
1 | println "Available scripts:
2 | checkUpdate - checks updates on GitHub
3 | own - own package manager
4 |
5 | To run a script use command:
6 | ownlang run checkUpdate
7 | "
--------------------------------------------------------------------------------
/ownlang-desktop/src/main/resources/scripts/own/Projects.own:
--------------------------------------------------------------------------------
1 | use files
2 |
3 | class Projects {
4 | def Projects(ctx) {
5 | this.ctx = ctx
6 | this.defaultPrograms = {
7 | "main.own" : "use std\n\necho(\"Hello, world!\", ARGS)"
8 | }
9 | }
10 |
11 | def savePrograms() {
12 | this.ctx.logger.debug("Projects.savePrograms")
13 | for name, content : this.defaultPrograms {
14 | if exists(name) continue
15 | f = fopen(name, "w")
16 | writeText(f, content)
17 | flush(f)
18 | fclose(f)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ownlang-parser/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | }
4 |
5 | group = 'com.annimon'
6 | version = versions.project
7 |
8 | dependencies {
9 | api project(':ownlang-core')
10 |
11 | testImplementation project(':modules:main')
12 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
13 | testImplementation 'org.junit.jupiter:junit-jupiter'
14 | testImplementation "org.junit.jupiter:junit-jupiter-params"
15 | testImplementation("org.assertj:assertj-core:${versions.assertj}")
16 | testImplementation "org.openjdk.jmh:jmh-core:${versions.jmh}"
17 | testImplementation "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}"
18 | testAnnotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}"
19 | }
20 |
21 | test {
22 | useJUnitPlatform()
23 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/OwnLangParserException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.SourceLocatedError;
4 | import java.util.Collection;
5 | import java.util.List;
6 |
7 | /**
8 | * Single Exception for Lexer, Parser and Linter errors
9 | */
10 | public class OwnLangParserException extends RuntimeException {
11 |
12 | private final Collection extends SourceLocatedError> errors;
13 |
14 | public OwnLangParserException(SourceLocatedError error) {
15 | super(error.toString());
16 | errors = List.of(error);;
17 | }
18 |
19 | public OwnLangParserException(Collection extends SourceLocatedError> errors) {
20 | super(errors.toString());
21 | this.errors = errors;
22 | }
23 |
24 | public Collection extends SourceLocatedError> getParseErrors() {
25 | return errors;
26 | }
27 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/ParseException.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.exceptions;
2 |
3 | import com.annimon.ownlang.util.Range;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public final class ParseException extends RuntimeException {
10 |
11 | private final Range range;
12 |
13 | public ParseException(String message, Range range) {
14 | super(message);
15 | this.range = range;
16 | }
17 |
18 | public Range getRange() {
19 | return range;
20 | }
21 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ParserMetadata.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser;
2 |
3 | public record ParserMetadata(
4 | String basePath
5 | ) {
6 | }
7 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/SourceLoader.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.nio.charset.StandardCharsets;
8 |
9 | public final class SourceLoader {
10 |
11 | private SourceLoader() { }
12 |
13 | public static String readSource(String name) throws IOException {
14 | InputStream is = SourceLoader.class.getResourceAsStream("/" + name);
15 | if (is != null) return readAndCloseStream(is);
16 |
17 | is = new FileInputStream(name);
18 | return readAndCloseStream(is);
19 | }
20 |
21 | public static String readAndCloseStream(InputStream is) throws IOException {
22 | final ByteArrayOutputStream result = new ByteArrayOutputStream();
23 | final int bufferSize = 1024;
24 | final byte[] buffer = new byte[bufferSize];
25 | int read;
26 | while ((read = is.read(buffer)) != -1) {
27 | result.write(buffer, 0, read);
28 | }
29 | is.close();
30 | return result.toString(StandardCharsets.UTF_8);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Token.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser;
2 |
3 | import com.annimon.ownlang.util.Pos;
4 |
5 | /**
6 | * @author aNNiMON
7 | */
8 | public record Token(TokenType type, String text, Pos pos) {
9 |
10 | public String shortDescription() {
11 | return type().name() + " " + text;
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return type.name() + " " + pos().format() + " " + text;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Accessible.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | public interface Accessible extends Node {
6 |
7 | Value get();
8 |
9 | Value set(Value value);
10 | }
11 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Argument.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | public record Argument(String name, Node valueExpr) {
4 |
5 | public Argument(String name) {
6 | this(name, null);
7 | }
8 |
9 | @Override
10 | public String toString() {
11 | return name + (valueExpr == null ? "" : " = " + valueExpr);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ArrayExpression.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.ArrayValue;
4 | import com.annimon.ownlang.lib.Value;
5 | import java.util.List;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public final class ArrayExpression implements Node {
12 |
13 | public final List elements;
14 |
15 | public ArrayExpression(List arguments) {
16 | this.elements = arguments;
17 | }
18 |
19 | @Override
20 | public Value eval() {
21 | final int size = elements.size();
22 | final ArrayValue array = new ArrayValue(size);
23 | for (int i = 0; i < size; i++) {
24 | array.set(i, elements.get(i).eval());
25 | }
26 | return array;
27 | }
28 |
29 | @Override
30 | public void accept(Visitor visitor) {
31 | visitor.visit(this);
32 | }
33 |
34 | @Override
35 | public R accept(ResultVisitor visitor, T t) {
36 | return visitor.visit(this, t);
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return elements.toString();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/BreakStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 | import com.annimon.ownlang.util.Range;
5 | import com.annimon.ownlang.util.SourceLocation;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public final class BreakStatement extends RuntimeException implements Statement, SourceLocation {
12 | private final Range range;
13 |
14 | public BreakStatement(Range range) {
15 | this.range = range;
16 | }
17 |
18 | @Override
19 | public Range getRange() {
20 | return range;
21 | }
22 |
23 | @Override
24 | public Value eval() {
25 | throw this;
26 | }
27 |
28 | @Override
29 | public void accept(Visitor visitor) {
30 | visitor.visit(this);
31 | }
32 |
33 | @Override
34 | public R accept(ResultVisitor visitor, T t) {
35 | return visitor.visit(this, t);
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return "break";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ContinueStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 | import com.annimon.ownlang.util.Range;
5 | import com.annimon.ownlang.util.SourceLocation;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public final class ContinueStatement extends RuntimeException implements Statement, SourceLocation {
12 | private final Range range;
13 |
14 | public ContinueStatement(Range range) {
15 | this.range = range;
16 | }
17 |
18 | @Override
19 | public Range getRange() {
20 | return range;
21 | }
22 |
23 | @Override
24 | public Value eval() {
25 | throw this;
26 | }
27 |
28 | @Override
29 | public void accept(Visitor visitor) {
30 | visitor.visit(this);
31 | }
32 |
33 | @Override
34 | public R accept(ResultVisitor visitor, T t) {
35 | return visitor.visit(this, t);
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return "continue";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ExprStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | /**
6 | * Wrapper for expressions, which can be used as statements.
7 | *
8 | * @author aNNiMON
9 | */
10 | public final class ExprStatement extends InterruptableNode implements Statement {
11 |
12 | public final Node expr;
13 |
14 | public ExprStatement(Node function) {
15 | this.expr = function;
16 | }
17 |
18 | @Override
19 | public Value eval() {
20 | super.interruptionCheck();
21 | return expr.eval();
22 | }
23 |
24 | @Override
25 | public void accept(Visitor visitor) {
26 | visitor.visit(this);
27 | }
28 |
29 | @Override
30 | public R accept(ResultVisitor visitor, T t) {
31 | return visitor.visit(this, t);
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return expr.toString();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionReferenceExpression.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.*;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public final class FunctionReferenceExpression extends InterruptableNode {
10 |
11 | public final String name;
12 |
13 | public FunctionReferenceExpression(String name) {
14 | this.name = name;
15 | }
16 |
17 | @Override
18 | public FunctionValue eval() {
19 | super.interruptionCheck();
20 | return new FunctionValue(ScopeHandler.getFunction(name));
21 | }
22 |
23 | @Override
24 | public void accept(Visitor visitor) {
25 | visitor.visit(this);
26 | }
27 |
28 | @Override
29 | public R accept(ResultVisitor visitor, T t) {
30 | return visitor.visit(this, t);
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return "::" + name;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/InterruptableNode.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.exceptions.StoppedException;
4 |
5 | public abstract class InterruptableNode implements Node {
6 |
7 | public static final int RUNNING = 0, PAUSED = 1, STOPPED = 2;
8 |
9 | private static volatile int state;
10 |
11 | public static void run() {
12 | state = RUNNING;
13 | }
14 |
15 | public static void pause() {
16 | state = PAUSED;
17 | }
18 |
19 | public static void stop() {
20 | state = STOPPED;
21 | }
22 |
23 | protected void interruptionCheck() {
24 | if (state == RUNNING) return;
25 | if (state == STOPPED) {
26 | throw new StoppedException();
27 | }
28 | try {
29 | while (state == PAUSED) {
30 | Thread.sleep(1000);
31 | }
32 | } catch (InterruptedException ioe) {
33 | Thread.currentThread().interrupt();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Node.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public interface Node {
10 |
11 | Value eval();
12 |
13 | void accept(Visitor visitor);
14 |
15 | R accept(ResultVisitor visitor, T input);
16 | }
17 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/PrintStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.lib.NumberValue;
5 | import com.annimon.ownlang.lib.Value;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public final class PrintStatement extends InterruptableNode implements Statement {
12 |
13 | public final Node expression;
14 |
15 | public PrintStatement(Node expression) {
16 | this.expression = expression;
17 | }
18 |
19 | @Override
20 | public Value eval() {
21 | super.interruptionCheck();
22 | Console.print(expression.eval().asString());
23 | return NumberValue.ZERO;
24 | }
25 |
26 | @Override
27 | public void accept(Visitor visitor) {
28 | visitor.visit(this);
29 | }
30 |
31 | @Override
32 | public R accept(ResultVisitor visitor, T t) {
33 | return visitor.visit(this, t);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "print " + expression;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/PrintlnStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.lib.NumberValue;
5 | import com.annimon.ownlang.lib.Value;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public final class PrintlnStatement extends InterruptableNode implements Statement {
12 |
13 | public final Node expression;
14 |
15 | public PrintlnStatement(Node expression) {
16 | this.expression = expression;
17 | }
18 |
19 | @Override
20 | public Value eval() {
21 | super.interruptionCheck();
22 | Console.println(expression.eval().asString());
23 | return NumberValue.ZERO;
24 | }
25 |
26 | @Override
27 | public void accept(Visitor visitor) {
28 | visitor.visit(this);
29 | }
30 |
31 | @Override
32 | public R accept(ResultVisitor visitor, T t) {
33 | return visitor.visit(this, t);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "println " + expression;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ReturnStatement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public final class ReturnStatement extends RuntimeException implements Statement {
10 |
11 | public final Node expression;
12 | private Value result;
13 |
14 | public ReturnStatement(Node expression) {
15 | this.expression = expression;
16 | }
17 |
18 | public Value getResult() {
19 | return result;
20 | }
21 |
22 | @Override
23 | public Value eval() {
24 | result = expression.eval();
25 | throw this;
26 | }
27 |
28 | @Override
29 | public void accept(Visitor visitor) {
30 | visitor.visit(this);
31 | }
32 |
33 | @Override
34 | public R accept(ResultVisitor visitor, T t) {
35 | return visitor.visit(this, t);
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return "return " + expression;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Statement.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | /**
4 | *
5 | * @author aNNiMON
6 | */
7 | public interface Statement extends Node {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/TernaryExpression.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public final class TernaryExpression implements Node {
10 |
11 | public final Node condition;
12 | public final Node trueExpr, falseExpr;
13 |
14 | public TernaryExpression(Node condition, Node trueExpr, Node falseExpr) {
15 | this.condition = condition;
16 | this.trueExpr = trueExpr;
17 | this.falseExpr = falseExpr;
18 | }
19 |
20 | @Override
21 | public Value eval() {
22 | if (condition.eval().asInt() != 0) {
23 | return trueExpr.eval();
24 | } else {
25 | return falseExpr.eval();
26 | }
27 | }
28 |
29 | @Override
30 | public void accept(Visitor visitor) {
31 | visitor.visit(this);
32 | }
33 |
34 | @Override
35 | public R accept(ResultVisitor visitor, T t) {
36 | return visitor.visit(this, t);
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return String.format("%s ? %s : %s", condition, trueExpr, falseExpr);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseError.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.error;
2 |
3 | import com.annimon.ownlang.util.Range;
4 | import com.annimon.ownlang.util.SourceLocatedError;
5 |
6 | public record ParseError(
7 | String message,
8 | Range range,
9 | StackTraceElement[] stackTraceElements
10 | ) implements SourceLocatedError {
11 |
12 | public ParseError(String message, Range range) {
13 | this(message, range, new StackTraceElement[0]);
14 | }
15 |
16 | @Override
17 | public String getMessage() {
18 | return message;
19 | }
20 |
21 | @Override
22 | public Range getRange() {
23 | return range;
24 | }
25 |
26 | @Override
27 | public StackTraceElement[] getStackTrace() {
28 | return stackTraceElements;
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "Error on line " + range().start().row() + ": " + message;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseErrorsFormatterStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.error;
2 |
3 | import com.annimon.ownlang.stages.Stage;
4 | import com.annimon.ownlang.stages.StagesData;
5 | import com.annimon.ownlang.util.ErrorsLocationFormatterStage;
6 | import com.annimon.ownlang.util.ErrorsStackTraceFormatterStage;
7 | import com.annimon.ownlang.util.SourceLocatedError;
8 | import java.util.Collection;
9 |
10 | public class ParseErrorsFormatterStage implements Stage, String> {
11 |
12 | @Override
13 | public String perform(StagesData stagesData, Collection extends SourceLocatedError> input) {
14 | String error = new ErrorsLocationFormatterStage()
15 | .perform(stagesData, input);
16 | String stackTrace = new ErrorsStackTraceFormatterStage()
17 | .perform(stagesData, input);
18 | return error + "\n" + stackTrace;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/DefaultFunctionsOverrideValidator.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.linters;
2 |
3 | import com.annimon.ownlang.parser.ast.*;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | final class DefaultFunctionsOverrideValidator extends LintVisitor {
8 |
9 | private final Set moduleFunctions = new HashSet<>();
10 |
11 | DefaultFunctionsOverrideValidator(LinterResults results) {
12 | super(results);
13 | }
14 |
15 | @Override
16 | public void visit(FunctionDefineStatement s) {
17 | super.visit(s);
18 | if (moduleFunctions.contains(s.name)) {
19 | results.add(LinterResult.warning(
20 | "Function \"%s\" overrides default module function".formatted(s.name)));
21 | }
22 | }
23 |
24 | @Override
25 | public void visit(IncludeStatement s) {
26 | super.visit(s);
27 | applyVisitor(s, this);
28 | }
29 |
30 | @Override
31 | public void visit(UseStatement s) {
32 | super.visit(s);
33 | moduleFunctions.addAll(s.loadFunctions().keySet());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LintVisitor.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.linters;
2 |
3 | import com.annimon.ownlang.parser.ast.IncludeStatement;
4 | import com.annimon.ownlang.parser.ast.Node;
5 | import com.annimon.ownlang.parser.ast.Visitor;
6 | import com.annimon.ownlang.parser.visitors.AbstractVisitor;
7 | import com.annimon.ownlang.parser.visitors.VisitorUtils;
8 |
9 | abstract class LintVisitor extends AbstractVisitor {
10 | protected final LinterResults results;
11 |
12 | LintVisitor(LinterResults results) {
13 | this.results = results;
14 | }
15 |
16 | protected void applyVisitor(IncludeStatement s, Visitor visitor) {
17 | final Node program = VisitorUtils.includeProgram(s);
18 | if (program != null) {
19 | program.accept(visitor);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/Optimizable.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.optimization;
2 |
3 | import com.annimon.ownlang.parser.ast.Node;
4 |
5 | public interface Optimizable {
6 |
7 | Node optimize(Node node);
8 |
9 | int optimizationsCount();
10 |
11 | String summaryInfo();
12 | }
13 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/VariableInfo.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.optimization;
2 |
3 | import com.annimon.ownlang.lib.Value;
4 |
5 | public final class VariableInfo {
6 | public Value value;
7 | int modifications;
8 |
9 | @Override
10 | public String toString() {
11 | return (value == null ? "?" : value) + " (" + modifications + " mods)";
12 | }
13 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/FunctionAdder.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.visitors;
2 |
3 | import com.annimon.ownlang.parser.ast.*;
4 |
5 | /**
6 | *
7 | * @author aNNiMON
8 | */
9 | public final class FunctionAdder extends AbstractVisitor {
10 |
11 | @Override
12 | public void visit(FunctionDefineStatement s) {
13 | super.visit(s);
14 | s.eval();
15 | }
16 |
17 | @Override
18 | public void visit(ClassDeclarationStatement s) {
19 | // skip, otherwise class methods will be visible outside of class
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/ModuleDetector.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.visitors;
2 |
3 | import com.annimon.ownlang.parser.ast.Node;
4 | import com.annimon.ownlang.parser.ast.UseStatement;
5 | import java.util.HashSet;
6 | import java.util.Set;
7 |
8 | public class ModuleDetector extends AbstractVisitor {
9 |
10 | private final Set modules;
11 |
12 | public ModuleDetector() {
13 | modules = new HashSet<>();
14 | }
15 |
16 | public Set detect(Node s) {
17 | s.accept(this);
18 | return modules;
19 | }
20 |
21 | @Override
22 | public void visit(UseStatement s) {
23 | modules.addAll(s.modules);
24 | super.visit(s);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/VariablePrinter.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.visitors;
2 |
3 | import com.annimon.ownlang.Console;
4 | import com.annimon.ownlang.parser.ast.*;
5 |
6 | /**
7 | *
8 | * @author aNNiMON
9 | */
10 | public final class VariablePrinter extends AbstractVisitor {
11 |
12 | @Override
13 | public void visit(AssignmentExpression s) {
14 | super.visit(s);
15 | Console.println(s.target);
16 | }
17 |
18 | @Override
19 | public void visit(VariableExpression s) {
20 | super.visit(s);
21 | Console.println(s.name);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/stages/ExecutionStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import com.annimon.ownlang.parser.ast.Node;
4 |
5 | public class ExecutionStage implements Stage {
6 |
7 | @Override
8 | public Node perform(StagesData stagesData, Node input) {
9 | input.eval();
10 | return input;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/stages/FunctionAddingStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import com.annimon.ownlang.parser.ast.Node;
4 | import com.annimon.ownlang.parser.visitors.FunctionAdder;
5 |
6 | public class FunctionAddingStage implements Stage {
7 |
8 | @Override
9 | public Node perform(StagesData stagesData, Node input) {
10 | input.accept(new FunctionAdder());
11 | return input;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ownlang-parser/src/main/java/com/annimon/ownlang/stages/LexerStage.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.stages;
2 |
3 | import com.annimon.ownlang.parser.Lexer;
4 | import com.annimon.ownlang.parser.Token;
5 | import java.util.List;
6 |
7 | public class LexerStage implements Stage> {
8 |
9 | public static final String TAG_TOKENS = "tokens";
10 |
11 | @Override
12 | public List perform(StagesData stagesData, String input) {
13 | Lexer lexer = new Lexer(input);
14 | List tokens = lexer.tokenize();
15 | stagesData.put(TAG_TOKENS, tokens);
16 | return tokens;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/java/com/annimon/ownlang/parser/TestDataUtil.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser;
2 |
3 | import java.io.File;
4 | import java.util.Arrays;
5 | import java.util.stream.Stream;
6 |
7 | public class TestDataUtil {
8 |
9 | static Stream scanDirectory(String dirPath) {
10 | return scanDirectory(new File(dirPath));
11 | }
12 |
13 | static Stream scanDirectory(File dir) {
14 | final File[] files = dir.listFiles();
15 | if (files == null || files.length == 0) {
16 | return Stream.empty();
17 | }
18 | return Arrays.stream(files)
19 | .flatMap(f -> f.isDirectory() ? scanDirectory(f) : Stream.of(f))
20 | .filter(f -> f.getName().endsWith(".own"));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ast/ValueExpressionTest.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.parser.ast;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static com.annimon.ownlang.parser.ast.ASTHelper.*;
6 |
7 | /**
8 | *
9 | * @author aNNiMON
10 | */
11 | public class ValueExpressionTest {
12 |
13 | @Test
14 | public void testValue() {
15 | assertValue(number(4), value(4).eval());
16 | assertValue(string("ABCD"), value("ABCD").eval());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/java/interop/Data.java:
--------------------------------------------------------------------------------
1 | package interop;
2 |
3 | public final class Data {
4 | public final int intValue = 3228;
5 | public final int[] intArrayValue = {1, 2, 3};
6 | public final Object nullObject = null;
7 | public final String stringValue = "str";
8 | public final String[] stringArrayValue = {"abc", "test"};
9 | public final Object[] objectArray = new Object[] {intValue, intArrayValue, nullObject, stringValue, stringArrayValue};
10 | public final Object compoundObject = objectArray;
11 |
12 | public void method() {
13 | System.out.println("method");
14 | }
15 |
16 | public String methodWithResult() {
17 | return "result";
18 | }
19 |
20 |
21 | private int value;
22 | private String text;
23 |
24 | public void set(int value) {
25 | this.value = value;
26 | }
27 |
28 | public void set(String text) {
29 | this.text = text;
30 | }
31 |
32 | public int getValue() {
33 | return value;
34 | }
35 |
36 | public String getText() {
37 | return text;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/benchmarks/calculator.own:
--------------------------------------------------------------------------------
1 | // Simple parser example
2 | use std, types
3 |
4 | operations = {
5 | "+" : def(a,b) = a+b,
6 | "-" : def(a,b) = a-b,
7 | "*" : def(a,b) = a*b,
8 | "/" : def(a,b) = a/b,
9 | "%" : def(a,b) = a%b,
10 | ">" : def(a,b) = a>b,
11 | "<" : def(a,b) = a4")
46 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/benchmarks/useStatement.own:
--------------------------------------------------------------------------------
1 | for i = 0, i < 50, i++ {
2 | use std
3 | use files
4 | use math, functional
5 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/assignmentExpression.own:
--------------------------------------------------------------------------------
1 | def testSimpleAssignment() {
2 | a = 8
3 | b = "str"
4 | assertEquals(8, a)
5 | assertEquals("str", b)
6 | }
7 |
8 | def testPrefixIncrement() {
9 | a = 8
10 | assertEquals(9, ++a)
11 | assertEquals(9, a)
12 | }
13 |
14 | def testPostfixIncrement() {
15 | a = 8
16 | assertEquals(8, a++)
17 | assertEquals(9, a)
18 | }
19 |
20 | def testPrefixDecrement() {
21 | a = 8
22 | assertEquals(7, --a)
23 | assertEquals(7, a)
24 | }
25 |
26 | def testPostfixDecrement() {
27 | a = 8
28 | assertEquals(8, a--)
29 | assertEquals(7, a)
30 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/binaryExpressionOnStrings.own:
--------------------------------------------------------------------------------
1 | def testStringConcatenation() {
2 | assertEquals("22", "2" + "2")
3 | assertEquals("22", "2" + 2)
4 | }
5 |
6 | def testStringMultiplication() {
7 | assertEquals("******", "*" * 6)
8 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/binaryUnaryExpr.own:
--------------------------------------------------------------------------------
1 | def testAdditionOnNumbers() {
2 | assertEquals(6, 0 + 1 + 2 + 3)
3 | }
4 |
5 | def testSubtractionOnNumbers() {
6 | assertEquals(-6, 0 - 1 - 2 - 3)
7 | }
8 |
9 | def testPrefixIncrement() {
10 | a = 8
11 | assertEquals(9, ++a)
12 | assertEquals(9, a)
13 | }
14 |
15 | def testPostfixIncrement() {
16 | a = 8
17 | assertEquals(8, a++)
18 | assertEquals(9, a)
19 | }
20 |
21 | def testStringReversing() {
22 | assertEquals("tset", -"test")
23 | }
24 |
25 | def testStringMultiplication() {
26 | assertEquals("******", "*" * 6)
27 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/foreachKeyValue.own:
--------------------------------------------------------------------------------
1 | def testArrayIterate() {
2 | sum = 0
3 | for v, i : [1, 2, 3] {
4 | sum += v * i
5 | }
6 | assertEquals(1 * 0 + 2 * 1 + 3 * 2, sum)
7 | }
8 |
9 | def testMapIterate() {
10 | map = {12: 1, 13: 2, 14: 3}
11 | sumKey = 0
12 | sumValue = 0
13 | for key, value : map {
14 | sumKey += key
15 | sumValue += value
16 | }
17 | assertEquals(39, sumKey)
18 | assertEquals(6, sumValue)
19 | }
20 |
21 | def testStringIterate() {
22 | str = ""
23 | sum = 0
24 | for s, code : "abcd" {
25 | str += s.upper
26 | sum += code
27 | }
28 | assertEquals("ABCD", str)
29 | assertEquals(394/*97 + 98 + 99 + 100*/, sum)
30 | }
31 |
32 | def testScope() {
33 | a = 100
34 | b = 200
35 | sum = 0
36 | for a, b : {14: 3} {
37 | sum += a
38 | sum += b
39 | }
40 | assertEquals(17, sum)
41 | assertEquals(14, a)
42 | assertEquals(3, b)
43 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/foreachValue.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testArrayIterate() {
4 | sum = 0
5 | for v : [1, 2, 3] {
6 | sum += v
7 | }
8 | assertEquals(6, sum)
9 | }
10 |
11 | def testMapIterate() {
12 | map = {12: 1, 13: 2, 14: 3}
13 | sumKey = 0
14 | sumValue = 0
15 | for pair : map {
16 | extract(key, value) = pair
17 | sumKey += key
18 | sumValue += value
19 | }
20 | assertEquals(39, sumKey)
21 | assertEquals(6, sumValue)
22 | }
23 |
24 | def testStringIterate() {
25 | sum = 0
26 | for s : "abcd" {
27 | sum += s.charAt(0)
28 | }
29 | assertEquals(394/*97 + 98 + 99 + 100*/, sum)
30 | }
31 |
32 | def testScope() {
33 | v = 45
34 | sum = 0
35 | for v : [1, 2, 3] {
36 | sum += v
37 | }
38 | assertEquals(6, sum)
39 | assertEquals(3, v)
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/functionReference.own:
--------------------------------------------------------------------------------
1 | def func() = "function"
2 | var = def() = "variable"
3 | def consumer(x) = x();
4 |
5 | assertEquals("function", consumer(::func))
6 | assertEquals("variable", consumer(var))
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/include.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testIncludeClass() {
4 | include "includeClass.own.txt"
5 | obj = new IncludeClass()
6 | assertEquals("1", obj.field1)
7 | assertEquals(2, obj.field2)
8 | assertEquals(42, obj.test())
9 | }
10 |
11 | def testIncludeNotExistsSource() {
12 | assertFail(def() {
13 | include "test.own"
14 | })
15 | }
16 |
17 | def testCatchingIncludeNotExistsSource() {
18 | res = try(def() {
19 | include "test.own"
20 | }, def(classname, message) = "ok")
21 | assertEquals("ok", res)
22 | }
23 |
24 | def testIncludeParseErrorSource() {
25 | assertFail(def() {
26 | include "includeParseErrorSource.own.txt"
27 | })
28 | }
29 |
30 | def testCatchingIncludeParseErrorSource() {
31 | res = try(def() {
32 | include "includeParseErrorSource.own.txt"
33 | }, def(classname, message) = "ok")
34 | assertEquals("ok", res)
35 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/includeClass.own.txt:
--------------------------------------------------------------------------------
1 | class IncludeClass {
2 | field1 = "1"
3 | field2 = 2
4 |
5 | def test() {
6 | return 42
7 | }
8 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/includeParseErrorSource.own.txt:
--------------------------------------------------------------------------------
1 | def test() = return println match x {
2 | case case 1
3 | }
4 | value = "passed"
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/nullCoalesce.own:
--------------------------------------------------------------------------------
1 | def testZero() {
2 | assertEquals(0, 0 ?? 1)
3 | x = 0
4 | assertEquals(0, x ?? 2)
5 | }
6 |
7 | def testObject() {
8 | obj = {"a": 12}
9 | assertEquals(12, obj.a ?? 10)
10 | }
11 |
12 | def testObjectMissingKey() {
13 | obj = {"a": 12}
14 | assertEquals(10, obj.test ?? 10)
15 | }
16 |
17 | def testNestedObjects() {
18 | obj = {"a": {"b": 12}}
19 | assertEquals(12, obj.a.b ?? 10)
20 | }
21 |
22 | def testNestedObjectsMissingKey() {
23 | obj = {"a": {"b": 12}}
24 | assertEquals(1, obj.test ?? 1)
25 | assertEquals(2, obj.a.test ?? 2)
26 | assertEquals(3, obj.test1.test2 ?? 3)
27 | }
28 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/unaryExpressionOnStrings.own:
--------------------------------------------------------------------------------
1 | def testStringReversing() {
2 | assertEquals("tset", -"test")
3 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/expressions/varFuncSameName.own:
--------------------------------------------------------------------------------
1 | def function() = "function"
2 | function = "variable"
3 |
4 | assertEquals("variable", function)
5 | assertEquals("function", function())
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/date/compareDates.own:
--------------------------------------------------------------------------------
1 | use date
2 |
3 | def testCompareDates() {
4 | assertTrue(newDate(2016, 04, 10) > newDate(2015, 03, 11))
5 | assertTrue(newDate(2012, 04, 10) < newDate(2015, 03, 11))
6 | assertTrue(newDate(2015, 03, 11, 0, 0, 0) == newDate(2015, 03, 11))
7 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/date/dateFormat.own:
--------------------------------------------------------------------------------
1 | use date
2 |
3 | def testDateFormat() {
4 | d = formatDate(newDate(2016, 04, 10), newFormat("yyyy/MM/dd HH:mm:ss"))
5 | assertEquals("2016/05/10 00:00:00", d)
6 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/date/dateParse.own:
--------------------------------------------------------------------------------
1 | use date
2 |
3 | def testDateParse() {
4 | d = parseDate("2016/05/10", newFormat("yyyy/MM/dd"))
5 | assertEquals(2016, d.year)
6 | assertEquals(4, d.month)
7 | assertEquals(10, d.day)
8 | assertEquals(0, d.hour)
9 | }
10 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/date/newDate.own:
--------------------------------------------------------------------------------
1 | use date
2 |
3 | def testNewDate() {
4 | d = newDate(2016, 04, 10)
5 | assertEquals(2016, d.year)
6 | assertEquals(4, d.month)
7 | assertEquals(10, d.day)
8 | assertEquals(0, d.hour)
9 | assertEquals(0, d.minute)
10 | assertEquals(0, d.second)
11 | assertEquals(0, d.millisecond)
12 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/files/files.own:
--------------------------------------------------------------------------------
1 | use files, types
2 |
3 | def testFiles() {
4 | // writeLong
5 | f = fopen("test.file", "wb")
6 | writeLong(f, 1002003004005006007)
7 | flush(f)
8 | fclose(f)
9 |
10 | // append & writeFloat
11 | fpNumber = 100200.3004005006007
12 | f = fopen("test.file", "wb+")
13 | writeFloat(f, fpNumber)
14 | flush(f)
15 | fclose(f)
16 |
17 | f = fopen("test.file", "rb")
18 | assertEquals(1002003004005006007, readLong(f))
19 | assertEquals(float(fpNumber), readFloat(f))
20 | assertEquals(-1, readInt(f)) // EOF
21 | assertEquals(0, FILES_COMPARATOR(f, f))
22 | fclose(f)
23 |
24 | f = fopen("test.file", "i")
25 | delete(f)
26 | fclose(f)
27 | }
28 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/functional/chain.own:
--------------------------------------------------------------------------------
1 | use functional
2 |
3 | def testFunctionalChain() {
4 | data = [1,2,3,4,5,6,7]
5 | result = chain(data,
6 | ::filter, def(x) = x <= 4,
7 | ::sortby, def(x) = -x,
8 | ::map, def(x) = x * 2,
9 | )
10 | assertEquals([8,6,4,2], result)
11 | }
12 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/functional/foreach.own:
--------------------------------------------------------------------------------
1 | use std, functional
2 |
3 | def testArrayForeachArg() {
4 | sum = 0
5 | foreach([1, 2, 3], def(v) {
6 | sum += v
7 | })
8 | assertEquals(6, sum)
9 | }
10 |
11 | def testStringForeach1Arg() {
12 | sum = 0
13 | foreach("abcd", def(s) {
14 | sum += s.charAt(0)
15 | })
16 | assertEquals(394/*97 + 98 + 99 + 100*/, sum)
17 | }
18 |
19 | def testStringForeach2Args() {
20 | str = ""
21 | sum = 0
22 | foreach("abcd", def(s, code) {
23 | str += s.upper
24 | sum += code
25 | })
26 | assertEquals("ABCD", str)
27 | assertEquals(97 + 98 + 99 + 100, sum)
28 | }
29 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/functional/groupby.own:
--------------------------------------------------------------------------------
1 | use std, functional
2 |
3 | def testGroupByKeys() {
4 | data = [
5 | {"k1": 1, "k2": "a"},
6 | {"k1": 2, "k2": "b"},
7 | {"k1": 3, "k2": "c"},
8 | ]
9 | result = groupby(data, def(e) = e.k2)
10 | assertEquals([{"k1": 1, "k2": "a"}], result.a)
11 | assertEquals([{"k1": 2, "k2": "b"}], result.b)
12 | assertEquals([{"k1": 3, "k2": "c"}], result.c)
13 | }
14 |
15 | def testArraysGroupBy() {
16 | arr = [1, 2, 3, 4, 1, 2, 3, 1, 2, 3]
17 | result = groupby(arr, def(v) = v % 2 == 0)
18 | assertEquals([2, 4, 2, 2], result[true])
19 | assertEquals([1, 3, 1, 3, 1, 3], result[false])
20 | }
21 |
22 | def testMapsGroupBy() {
23 | map = {"abc": 123, "test1": 234, "test2": 345, "test3": 456, "def": 567}
24 | result = groupby(map, def(k, v) = k.startsWith("test"))
25 | assertEquals({"test1": 234, "test2": 345, "test3": 456}, result[true])
26 | assertEquals({"abc": 123, "def": 567}, result[false])
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/regex/match.own:
--------------------------------------------------------------------------------
1 | use regex, types
2 |
3 | def testMatchGitUrl() {
4 | pattern = Pattern.compile("https?://((git(hu|la)b\.com)|bitbucket\.org)/?")
5 | assertTrue(pattern.matches("http://github.com"))
6 | assertTrue(pattern.matches("http://github.com/"))
7 | assertTrue(pattern.matches("https://gitlab.com/"))
8 | assertTrue(pattern.matches("https://bitbucket.org/"))
9 |
10 | assertFalse(pattern.matches("http://github.org"))
11 | assertFalse(pattern.matches("https://bithub.com/"))
12 | assertFalse(pattern.matches("http://gitlab.org"))
13 | assertFalse(pattern.matches("ftp://github.com/"))
14 | assertFalse(pattern.matches("http://gitbucket.org/"))
15 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/regex/replaceCallback.own:
--------------------------------------------------------------------------------
1 | use regex, types
2 |
3 | def testReplaceCallback() {
4 | in = "[1-2-3-4]"
5 | pattern = regex("(\d)")
6 | out = pattern.replaceCallback(in, def(m) = m.group() * int(m.group()))
7 | assertEquals("[1-22-333-4444]", out)
8 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/default.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testDefaultNumber() {
4 | assertEquals(123, default(0, 123))
5 | }
6 |
7 | def testDefaultString() {
8 | assertEquals("123", default("", "123"))
9 | }
10 |
11 | def testDefaultNull() {
12 | use java
13 | assertEquals("not null", default(null, "not null"))
14 | }
15 |
16 | def testOperatorOverloading() {
17 | def `?:`(a, b) = default(a, b)
18 | assertEquals("not null", "" ?: "not null")
19 | }
20 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/getBytes.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testGetBytes() {
4 | assertEquals([111, 119, 110, 108, 97, 110, 103], getBytes("ownlang"))
5 | }
6 |
7 | def testGetBytesEmptyString() {
8 | assertEquals([], getBytes(""))
9 | }
10 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/indexOf.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testIndexOf() {
4 | assertEquals(3, indexOf("123/456/789", "/"))
5 | }
6 |
7 | def testIndexOfIndex() {
8 | assertEquals(7, indexOf("123/456/789", "/", 4))
9 | }
10 |
11 | def testIndexOfNonMatch() {
12 | assertEquals(-1, indexOf("123", "/"))
13 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/lastIndexOf.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testLastIndexOf() {
4 | assertEquals(8, lastIndexOf("/123/456/789", "/"))
5 | }
6 |
7 | def testLastIndexOfIndex() {
8 | assertEquals(4, lastIndexOf("/123/456/789", "/", 6))
9 | }
10 |
11 | def testLastIndexOfNonMatch() {
12 | assertEquals(-1, lastIndexOf("123", "/"))
13 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/parseInt.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testParseInt() {
4 | assertEquals(141, parseInt("141"))
5 | }
6 |
7 | def testParseIntBin() {
8 | assertEquals(141, parseInt("10001101", 2))
9 | }
10 |
11 | def testParseIntOct() {
12 | assertEquals(141, parseInt("215", 8))
13 | }
14 |
15 | def testParseIntHex() {
16 | assertEquals(141, parseInt("8D", 16))
17 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/parseLong.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testParseInt() {
4 | assertEquals(12345654321, parseLong("12345654321"))
5 | }
6 |
7 | def testParseIntBin() {
8 | assertEquals(12345654321, parseLong("1011011111110110111011110000110001", 2))
9 | }
10 |
11 | def testParseIntOct() {
12 | assertEquals(12345654321, parseLong("133766736061", 8))
13 | }
14 |
15 | def testParseIntHex() {
16 | assertEquals(#2DFDBBC31, parseLong("2DFDBBC31", 16))
17 | assertEquals(12345654321, parseLong("2DFDBBC31", 16))
18 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/stringFromBytes.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testStringFromBytes() {
4 | assertEquals("ownlang", stringFromBytes([111, 119, 110, 108, 97, 110, 103]))
5 | }
6 |
7 | def testStringFromEmptyString() {
8 | assertEquals("", stringFromBytes([]))
9 | }
10 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/toHexString.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testToHexString() {
4 | assertEquals("8d", toHexString(141))
5 | assertEquals("cafebabe", toHexString(#CAFEBABE))
6 | assertEquals("2dfdbbc31", toHexString(12345654321))
7 | }
8 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/std/try.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testTryOnly() {
4 | assertEquals(1, try(def() = 1))
5 | assertEquals(-1, try(def() = parseInt("oops")))
6 | }
7 |
8 | def testCatchFunction() {
9 | actual = try(def() = parseInt("oops"), def(clazz, cause) = clazz)
10 | assertEquals("java.lang.NumberFormatException", actual)
11 | }
12 |
13 | def testCatchValue() {
14 | actual = try(def() = parseInt("oops"), 42)
15 | assertEquals(42, actual)
16 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/yaml/yamldecode.own:
--------------------------------------------------------------------------------
1 | use std, yaml
2 |
3 | x = yamldecode("
4 | name: \"std\"
5 | scope: \"both\"
6 | desc: \"Contains common functions\"
7 | desc_ru: \"Содержит вспомогательные функции общего назначения\"
8 | constants: []
9 | functions:
10 | -
11 | name: \"arrayCombine\"
12 | args: \"keys, values\"
13 | desc: \"creates map by combining two arrays\"
14 | desc_ru: \"создаёт объект на основе двух массивов\"
15 | -
16 | name: \"typeof\"
17 | args: \"value\"
18 | desc: \"returns the type of value\"
19 | desc_ru: \"возвращает тип переданного значения\"
20 | example: |-
21 | print typeof(1) // 1 (NUMBER)
22 | print typeof(\"text\") // 2 (STRING)
23 | print typeof([]) // 3 (ARRAY)
24 | ")
25 |
26 | assertEquals("std", x.name)
27 | assertEquals("both", x.scope)
28 | assertEquals(0, x.constants.length)
29 | assertEquals(2, x.functions.length)
30 | assertEquals("arrayCombine", x.functions[0].name)
31 | assertEquals("возвращает тип переданного значения", x.functions[1].desc_ru)
32 |
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/modules/yaml/yamlencode.own:
--------------------------------------------------------------------------------
1 | use std, yaml
2 |
3 | yml = yamlencode({
4 | "name": "Yaml Example",
5 | "version": 1,
6 | "arrayData": [
7 | 1, 2, 3, 4
8 | ],
9 | "objectData": {
10 | "key": "value",
11 | 10: "1000"
12 | }
13 | })
14 | obj = yamldecode(yml)
15 |
16 | assertEquals("Yaml Example", obj.name)
17 | assertEquals(1, obj.version)
18 | assertEquals(4, length(obj.arrayData))
19 | assertEquals("value", obj.objectData.key)
20 | assertEquals("1000", obj.objectData["10"])
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/arrayFunctions.own:
--------------------------------------------------------------------------------
1 | def testSetUnknownKey() = assertFail(def() {
2 | arr = [1, 2, 3]
3 | arr.one = 1
4 | })
5 |
6 | def testSetLengthProperty() = assertFail(def() {
7 | arr = [1, 2, 3]
8 | arr.length = 10
9 | })
10 |
11 | def testGetLength() {
12 | arr = [1, 2, 3]
13 | assertEquals(3, arr.length)
14 | }
15 |
16 | def testGetLengthInnerArray() {
17 | arr = [[1, 2, 3], [1, 2, [3, 4, 5, 6]]]
18 | assertEquals(2, arr.length)
19 | assertEquals(3, arr[0].length)
20 | assertEquals(4, arr[1][2].length)
21 | }
22 |
23 | def testIsEmpty() {
24 | arr = [1, 2, 3]
25 | assertFalse(arr.isEmpty())
26 | }
27 |
28 | def testJoinToString() {
29 | arr = [1, 2, 3]
30 | assertEquals("123", arr.joinToString())
31 | assertEquals("1 2 3", arr.joinToString(" "))
32 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/classScope.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testThisOnSingleInstance() {
4 | s = new ClassScope({"id": 1})
5 | assertEquals(1, s.getId())
6 | assertEquals(1, s.getDataId())
7 | }
8 |
9 | def testThisOnMultipleInstances() {
10 | s1 = new ClassScope({"id": 1})
11 | s2 = new ClassScope({"id": 2})
12 | s3 = new ClassScope({"id": 3})
13 | assertEquals(1, s1.getId())
14 | assertEquals(1, s1.getDataId())
15 | assertEquals(2, s2.getId())
16 | assertEquals(2, s2.getDataId())
17 | assertEquals(3, s3.getId())
18 | assertEquals(3, s3.getDataId())
19 | }
20 | def testToString() {
21 | s1 = new ClassScope({"id": 1})
22 | s2 = new ClassScope({"id": 2})
23 | assertEquals("ClassScope{id=1}", s1.toString())
24 | assertEquals("ClassScope{id=2}", s2.toString())
25 | }
26 |
27 | class ClassScope {
28 | def ClassScope(data) {
29 | this.id = data.id
30 | this.data = data
31 | }
32 |
33 | def getId() {
34 | return this.id
35 | }
36 |
37 | def getDataId() {
38 | return this.data.id
39 | }
40 |
41 | def toString() {
42 | return "ClassScope{id=" + this.id + "}"
43 | }
44 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/functionChain.own:
--------------------------------------------------------------------------------
1 | def f1() = {"func": ::f2}
2 | def f2() = {
3 | "functions" : {
4 | "add" : def(a, b) = a + b
5 | "mul" : def(a, b) = a * b
6 | "negate" : def(a) = {"result" : -a}
7 | }
8 | }
9 | def f3() = def() = def() = def() = "test"
10 | def f4() = def() = ::f1
11 |
12 | def testFunctionChain() {
13 | assertEquals(5, f1().func().`functions`.add(2, 3))
14 | assertEquals(6, f1().func().`functions`.mul(2, 3))
15 | }
16 |
17 | def testCallChain() {
18 | assertEquals("test", f3()()()())
19 | }
20 |
21 | def testBoth() {
22 | assertEquals(-123, f4()()().func().`functions`.negate(123).result)
23 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/recursion.own:
--------------------------------------------------------------------------------
1 | def testFibonacci() {
2 | def fib(n) {
3 | if n < 2 return n
4 | return fib(n-2) + fib(n-1)
5 | }
6 | assertEquals(3, fib(4))
7 | assertEquals(21, fib(8))
8 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/scope.own:
--------------------------------------------------------------------------------
1 | def testScope() {
2 | x = 5
3 | def func() {
4 | assertEquals(5, x)
5 | x += 10
6 | assertEquals(15, x)
7 | }
8 | func();
9 | assertEquals(15, x)
10 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/types.own:
--------------------------------------------------------------------------------
1 | def testTypes() {
2 | assertSameType(0, 0.0)
3 | }
--------------------------------------------------------------------------------
/ownlang-parser/src/test/resources/other/useStatementScope.own:
--------------------------------------------------------------------------------
1 | use std
2 |
3 | def testRegular() {
4 | assertEquals("7f", "127".toHexString())
5 | }
6 |
7 | def testInCondition() {
8 | if (true) {
9 | use date
10 | }
11 | assertNotEquals("", newDate())
12 | }
13 |
14 | def testInScope() {
15 | PI = "fallback"
16 | assertEquals("fallback", PI)
17 |
18 | useMath()
19 | assertNotEquals("fallback", PI)
20 | assertEquals(3, abs(-3))
21 | }
22 |
23 | def useMath() {
24 | use math
25 | }
--------------------------------------------------------------------------------
/ownlang-utils/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | }
4 |
5 | group = 'com.annimon'
6 | version = versions.project
7 |
8 | dependencies {
9 | api project(":ownlang-parser")
10 | implementation "jline:jline:${versions.jline}"
11 |
12 | testImplementation platform("org.junit:junit-bom:${versions.junit}")
13 | testImplementation 'org.junit.jupiter:junit-jupiter'
14 | }
15 |
16 | test {
17 | useJUnitPlatform()
18 | }
19 |
--------------------------------------------------------------------------------
/ownlang-utils/src/main/java/com/annimon/ownlang/utils/repl/JLineConsole.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.utils.repl;
2 |
3 | import java.io.IOException;
4 | import jline.TerminalFactory;
5 | import jline.console.ConsoleReader;
6 |
7 | public class JLineConsole implements ReplConsole {
8 |
9 | private final ConsoleReader console;
10 |
11 | public JLineConsole() throws IOException {
12 | System.setProperty(ConsoleReader.JLINE_EXPAND_EVENTS, "false");
13 | console = new ConsoleReader();
14 | }
15 |
16 | public ConsoleReader getConsole() {
17 | return console;
18 | }
19 |
20 | @Override
21 | public void setPrompt(String prompt) {
22 | console.setPrompt(prompt);
23 | }
24 |
25 | @Override
26 | public String readLine() {
27 | try {
28 | return console.readLine();
29 | } catch (IOException ex) {
30 | return null;
31 | }
32 | }
33 |
34 | @Override
35 | public void close() {
36 | try {
37 | TerminalFactory.get().restore();
38 | } catch (Exception ignored) {
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/ownlang-utils/src/main/java/com/annimon/ownlang/utils/repl/ReplConsole.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.utils.repl;
2 |
3 | public interface ReplConsole {
4 |
5 | void setPrompt(String prompt);
6 |
7 | String readLine();
8 |
9 | void close();
10 | }
11 |
--------------------------------------------------------------------------------
/ownlang-utils/src/main/java/com/annimon/ownlang/utils/repl/SystemConsole.java:
--------------------------------------------------------------------------------
1 | package com.annimon.ownlang.utils.repl;
2 |
3 | import java.util.Scanner;
4 |
5 | public class SystemConsole implements ReplConsole {
6 |
7 | private final Scanner scanner;
8 |
9 | public SystemConsole() {
10 | scanner = new Scanner(System.in);
11 | }
12 |
13 | @Override
14 | public void setPrompt(String prompt) {
15 | System.out.print(prompt);
16 | }
17 |
18 | @Override
19 | public String readLine() {
20 | if (!scanner.hasNextLine()) {
21 | return null;
22 | }
23 | return scanner.nextLine();
24 | }
25 |
26 | @Override
27 | public void close() {
28 | scanner.close();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'OwnLang'
2 |
3 | include 'ownlang-core'
4 | include 'ownlang-parser'
5 | include 'ownlang-desktop'
6 | include 'ownlang-utils'
7 | include 'docs'
8 |
9 | final def modules = ['main', 'canvasfx', 'jdbc', 'server', 'socket']
10 |
11 | for (final def module in modules) {
12 | include "modules:$module"
13 | findProject(":modules:$module")?.name = module
14 | }
15 |
--------------------------------------------------------------------------------