zeolite

所属分类:Linux/Unix编程
开发工具:Haskell
文件大小:0KB
下载次数:0
上传日期:2023-06-02 03:34:02
上 传 者sh-1993
说明:  沸石是一种静态类型的通用编程语言。
(Zeolite is a statically-typed, general-purpose programming language.)

文件列表:
ChangeLog.md (62203, 2023-12-17)
LICENSE (10174, 2023-12-17)
Setup.hs (46, 2023-12-17)
base/ (0, 2023-12-17)
base/.zeolite-module (1233, 2023-12-17)
base/boxed.hpp (9094, 2023-12-17)
base/builtin.0rp (10763, 2023-12-17)
base/category-header.hpp (1009, 2023-12-17)
base/category-source.hpp (8078, 2023-12-17)
base/cleanup.hpp (1823, 2023-12-17)
base/cycle-check.hpp (1469, 2023-12-17)
base/function.hpp (5287, 2023-12-17)
base/logging.hpp (6265, 2023-12-17)
base/pooled.hpp (3675, 2023-12-17)
base/returns.hpp (2177, 2023-12-17)
base/src/ (0, 2023-12-17)
base/src/Builtin_Bool.cpp (3511, 2023-12-17)
base/src/Builtin_Char.cpp (4029, 2023-12-17)
base/src/Builtin_CharBuffer.cpp (4171, 2023-12-17)
base/src/Builtin_Float.cpp (3718, 2023-12-17)
base/src/Builtin_Identifier.cpp (3723, 2023-12-17)
base/src/Builtin_Int.cpp (4017, 2023-12-17)
base/src/Builtin_Pointer.cpp (2113, 2023-12-17)
base/src/Builtin_String.cpp (7808, 2023-12-17)
base/src/boxed.cpp (10015, 2023-12-17)
base/src/category-source.cpp (9180, 2023-12-17)
base/src/cleanup.cpp (1565, 2023-12-17)
base/src/logging.cpp (6472, 2023-12-17)
base/src/returns.cpp (2518, 2023-12-17)
base/src/thread-crosser.cc (42, 2023-12-17)
base/testing.0rp (888, 2023-12-17)
base/thread-capture.h (42, 2023-12-17)
base/thread-crosser.h (42, 2023-12-17)
base/types.hpp (5567, 2023-12-17)
... ...

# [Zeolite Programming Language][zeolite] [![Haskell CI Status][action-status]][action-zeolite] [![Hackage Status][hackage-status]][hackage-zeolite-lang] Zeolite is a statically-typed, general-purpose programming language. The type system revolves around defining objects and their usage patterns. Zeolite prioritizes making code written with it simple to understand for readers who didn't write the original code. This is done by limiting flexibility in some places and increasing it in others. In particular, emphasis is placed on the user's experience when troubleshooting code that is *incorrect*. The design of the type system and the language itself is influenced by positive and negative experiences with Java, C++, Haskell, Python, and Go, with collaborative development, and with various systems of code-quality enforcement. Due to the way GitHub renders embedded HTML, the colors might not show up in the syntax-highlighted code in this document. If you use the Chrome browser, you can view the intended formatting using the [Markdown Viewer](https://chrome.google.com/webstore/detail/markdown-viewer/ckkdlimhmcjmikdlpkmbgfkaikojcbjk) extension to view the [raw version](https://raw.githubusercontent.com/ta0kira/zeolite/master/README.md) of this document. ## Table of Contents - [Project Status](#project-status) - [Language Overview](#language-overview) - [Programming Paradigms](#programming-paradigms) - [Parameter Variance](#parameter-variance) - [Parameters as Variables](#parameters-as-variables) - [Integrated Test Runner](#integrated-test-runner) - [Integrated Build System](#integrated-build-system) - [Data Encapsulation](#data-encapsulation) - [Quick Start](#quick-start) - [Installation](#installation) - [Hello World](#hello-world) - [Writing Programs](#writing-programs) - [Basic Ideas](#basic-ideas) - [Declaring Functions](#declaring-functions) - [Defining Functions](#defining-functions) - [Using Variables](#using-variables) - [Calling Functions](#calling-functions) - [Functions As Operators](#functions-as-operators) - [Data Members and Value Creation](#data-members-and-value-creation) - [Conditionals](#conditionals) - [Scoping and Cleanup](#scoping-and-cleanup) - [Loops](#loops) - [Multiple Returns](#multiple-returns) - [Optional and Weak Values](#optional-and-weak-values) - [Deferred Variable Initialization](#deferred-variable-initialization) - [Immediate Program Termination](#immediate-program-termination) - [Call Delegation](#call-delegation) - [Function Argument Labels](#function-argument-labels) - [Using Parameters](#using-parameters) - [Using Interfaces](#using-interfaces) - [Immutable Types](#immutable-types) - [The `#self` Parameter](#the-self-parameter) - [Type Inference](#type-inference) - [Other Features](#other-features) - [Meta Types](#meta-types) - [Explicit Type Conversion](#explicit-type-conversion) - [Runtime Type Reduction](#runtime-type-reduction) - [Value Instance Comparison](#value-instance-comparison) - [Limited Function Visibility](#limited-function-visibility) - [Builtins](#builtins) - [Reserved Words](#reserved-words) - [Builtin Types](#builtin-types) - [Builtin Constants](#builtin-constants) - [Builtin Functions](#builtin-functions) - [Layout and Dependencies](#layout-and-dependencies) - [Using Public Source Files](#using-public-source-files) - [Standard Library](#standard-library) - [Modules](#modules) - [Unit Testing](#unit-testing) - [Writing Tests](#writing-tests) - [Code Coverage](#code-coverage) - [Compiler Pragmas and Macros](#compiler-pragmas-and-macros) - [Source File Pragmas](#source-file-pragmas) - [Procedure Pragmas](#procedure-pragmas) - [`define` Pragmas](#define-pragmas) - [`unittest` Pragmas](#unittest-pragmas) - [Local Variable Rules](#local-variable-rules) - [Expression Macros](#expression-macros) - [Known Language Limitations](#known-language-limitations) - [Reference Counting](#reference-counting) ## Project Status Zeolite is still evolving in all areas (syntax, build system, etc.), and it still lacks a lot of standard library functionality. That said, it was designed with practical applications in mind. It *does not* prioritize having impressive toy examples (e.g., merge-sort or "Hello World" in one line); the real value is seen in programs with higher relational complexity. ## Language Overview This section discusses some of the features that make Zeolite unique. It does not go into detail about all of the language's features; see [Writing Programs](#writing-programs) and the [full examples][examples] for more specific language information. ### Programming Paradigms Zeolite currently uses both [procedural][procedural] and [object-oriented][oop] programming paradigms. It shares many features with Java, but it also has additional features and restrictions meant to simplify code maintenance. ### Parameter Variance The initial motivation for Zeolite was a type system that allows implicit conversions between different parameterizations of parameterized types. A parameterized type is a type with type "place-holders", e.g., `template`s in C++ and generics in Java. Java and C++ *do not* allow you to safely convert between different parameterizations. For example, you cannot safely convert a `List` into a `List` in Java. This is primarily because `List` uses its type parameter for both input and output. Zeolite, on the other hand, uses [declaration-site variance][variance] for each parameter. (C# also does this to a lesser extent.) This allows the language to support very powerful recursive type conversions for parameterized types. Zeolite *also* allows [use-site variance][variance] declarations, like Java uses. Building variance into the core of the type system also allows Zeolite to have a [special meta-type](#the-self-parameter) that interfaces can use to require that implementations return a value of *their own type* rather than *the type of the interface*. This is particularly useful for defining interfaces for iterators and builders, whose methods often perform an update and return a value of the same type. ### Parameters as Variables Zeolite treats type parameters both as type place-holders (like in C++ and Java) and as *type variables* that you can call functions on. This further allows Zeolite to have interfaces that declare functions that operate on *types* in addition to interfaces that declare functions that operate on *values*. (This would be like having `abstract static` methods in Java.) This helps solve a few separate problems: - Operations like `equals` comparisons in Java are always dispatched to the *left* object, which could lead to inconsistent results if the objects are swapped: `foo.equals(bar)` is not the same as `bar.equals(foo)`. This dispatching asymmetry can be eliminated by making `equals` a type function (e.g., `MyType.equals(foo, bar)`), and further creating an interface that requires implementations to support such calls. - Factory patterns can be abstracted out into interfaces. For example, you could create a factory interface that requires an implementation to parse a new object from a `String`, without needing to instantiate the factory object itself. You could just implement the factory function directly in `MyType`, without needing a separate `MyTypeFactory`. ### Integrated Test Runner The major advantage of statically-typed programming languages is their compile-time detection of code that *should not* be allowed. On the other hand, there is a major testability gap when it comes to ensuring that your statically-typed code *disallows* what you expect it to. Zeolite has a special source-file extension for unit tests, and a built-in compiler mode to run them. - Tests can check for runtime success, compilation success, compilation failure, and even crashes. Normally you would need a third-party test runner to check for required compilation failures and crashes. - The test mode includes a command-line option to collect code-coverage data, which can be critical for determining test efficacy. Nearly all of the integration testing of the Zeolite language itself is done using this feature, but it is also supported for general use with Zeolite projects. ### Integrated Build System The Zeolite compiler supports a module system that can incrementally compile projects without the user needing to create build scripts or `Makefile`s. - Modules are configured via a simple config file. - File-level and symbol-level imports and includes *are not* necessary, allowing module authors to freely rearrange file structure. - Type dependencies are automatically resolved during linking so that output binaries contain only the code that is relevant. - Module authors can back Zeolite code with C++. - The module system is integrated with the compiler's built-in testing mode. This means that the programmer can focus on code rather than on build rules, and module authors can avoid writing verbose build instructions for the users of their modules. ### Data Encapsulation The overall design of Zeolite revolves around data encapsulation: - **No default construction or copying.** This means that objects can only be created by explicit factory functions. (A very common mistake in C++ code is forgetting to *disallow or override* default construction or copying.) This also means that accidental deep copying is not even possible in Zeolite. - **Only abstract interfaces can be inherited.** Types that define procedures or contain data members *cannot* be further extended. This encourages the programmer to think more about usage patterns and less about data representation when designing interactions between types. - **No "privileged" data-member access.** No object has *direct* access to the data members of any other object; not even other objects of the same type. This forces the programmer to also think about usage patterns when dealing with other objects of the same type. - **No `null` values.** Every variable must be explicitly initialized. This obviates questions of whether or not a variable actually contains a value. When combined with the elimination of default construction, this means that a variable can only hold values that a type author has specifically allowed. Zeolite has an `optional` storage modifier for use in a variable's type, but it creates a new and incompatible type, whose value cannot be used without first extracting it. This is in contrast to Java allowing any variable to be `null`. (It is more like `Optional` in Java 8, but as built-in syntax, and with nesting disallowed.) - **No reflection or down-casting.** The only thing that has access to the "real" type of a value is the value itself. This means that the reflection and down-casting tricks available in Java to circumvent the compiler *are not* available in Zeolite. (User-defined types can selectively allow "down-casting like" semantics by reasoning about [parameters as variables](#parameters-as-variables), however.) - **Implementation details are kept separate.** In Zeolite, only *public inheritance* and *public functions* show up where an object type is declared, to discourage relying on implementation details of the type. C++ and Java allow (and in some cases *require*) implementation details (data members, function definitions, etc.) to show up in the same place as the user-accessible parts of a `class`. The result is that the user of the `class` will often rely on knowledge of how it works internally. Although all of these limitations preclude a lot of design decisions allowed in languages like Java, C++, and Python, they also drastically reduce the possible complexity of inter-object interactions. Additionally, they generally *do not* require ugly work-arounds; see the [full examples][examples]. ## Quick Start ### Installation Requirements: - A POSIX-compliant operating system. Zeolite has been tested on Linux and FreeBSD, and to a limited extent on MacOS. It probably _won't_ work on Windows, due to how it interacts with the filesystem and subprocesses. - A Haskell compiler such as [`ghc`][ghc] that can install packages using [`cabal`][cabal], as well as the [`cabal`][cabal] installer. - A C++ compiler such as [`clang++`][clang] or [`g++`][gcc] and the standard `ar` archiver present on most Unix-like operating systems. If you use a modern Linux distribution, most of the above can be installed using the package manager that comes with your distribution. On MacOS, you can install [Xcode][xcode] for a C++ compiler and [`brew install cabal-install`][brew-cabal] for `cabal`. Once you meet all of those requirements, follow the installation instructions for the [**`zeolite-lang`**][hackage-zeolite-lang] package on [Hackage][hackage]. Please take a look at the [issues page][zeolite-issues] if you run into problems. The entire process will probably look like this, once you have `cabal` and a C++ compiler installed: ```shell $ cabal update # Also add --overwrite-policy=always if you're upgrading to a specific version. $ cabal install zeolite-lang $ zeolite-setup -j8 # Follow interactive prompts... ``` If you happen to use the [`kate`][kate] text editor, you can use the syntax highlighting in [`zeolite.xml`][zeolite.xml]. ### Hello World It's the [any%](https://en.wiktionary.org/wiki/any%25) of programming.
// hello-world.0rx

concrete HelloWorld {
  @type run () -> ()
}

define HelloWorld {
  run () {
    \ BasicOutput.stderr().writeNow("Hello World\n")
  }
}
```shell # Compile. zeolite -I lib/util --fast HelloWorld hello-world.0rx # Execute. ./HelloWorld ``` Also see some [full examples][examples] for more complete feature usage. ## Writing Programs This section breaks down the separate parts of a Zeolite program. See the [full examples][examples] for a more integrated language overview. ### Basic Ideas Zeolite programs use object-oriented and procedural programming paradigms. **Type categories** are used to define object types, much like `class`es in Java and C++. They *are not* called "classes", just to avoid confusion about semantic differences with Java and C++. All type-category names start with an uppercase letter and contain only letters and digits. All procedures and data live inside `concrete` type categories. Every program must have at least one `concrete` category with the procedure to be executed when the program is run. `concrete` categories are split into a **declaration** and a **definition**. Code for both should be in files ending with `.0rx`. (The `.0rp` file type contains only declarations, and will be discussed later.)
// myprogram/myprogram.0rx

// This declares the type.
concrete MyProgram {
  // The entry point must be a () -> () function. This means that it takes no
  // arguments and returns no arguments. (@type will be discussed later.)
  @type run () -> ()
}

// This defines the type.
define MyProgram {
  run () {
    // ...
  }
}
**IMPORTANT:** All programs or modules must be in their own directory so that `zeolite` is able to cache information about the build. Unlike some other compilers, you *do not* specify all command-line options every time you recompile a binary or module. ```shell # Create a new .zeolite-module config. (Only once!) zeolite -m MyProgram myprogram # Recompile the module and binary. (After any config or code updates.) # All sources in myprogram will be compiled. -m MyProgram selects the entry # point. The default output name for the binary here is myprogram/MyProgram. zeolite -r myprogram # Execute. myprogram/MyProgram ``` ```shell # An alternative, if you only have one .0rx and want to quickly iterate. zeolite --fast MyProgram myprogram/myprogram.0rx ``` ### Declaring Functions A **function declaration** specifies the **scope** of the function and its **argument** and **return** types. (And optionally type parameters and parameter filters, to be discussed later.) The declaration simply indicates the existence of a function, without specifying its behavior. All function names start with a lowercase letter and contain only letters and digits.
concrete MyCategory {
  // @value indicates that this function requires a value of type MyCategory.
  // This function takes 2x Int and returns 2x Int.
  @value minMax (Int, Int) -> (Int, Int)

  // @type indicates that this function operates on MyCategory itself. This is
  // like a static function in C++.
  // This function takes no arguments and returns MyCategory.
  @type create () -> (MyCategory)

  // @category indicates that this function operates on MyCategory itself. This
  // is like a static function in Java. (The semantics of @category are similar
  // to those of @type unless there are type parameters.)
  @category copy (MyCategory) -> (MyCategory)
}
In many cases, the choice between using a `@category` function or a `@type` function is arbitrary, but there are pros and cons of each: - **`@category` functions** *do not* inherit any of the [category's parameters](#using-parameters), or their filters. This can be useful in a few situations: 1. You want to impose additional restrictions on what parameters can be used. For example, `Vector:createSize` ([`lib/container`][lib/container]) requires that param `#y defines Default` so that it can populate the `Vector` with default values. 2. The caller will pass arguments that can be used to [infer the category's parameters](#type-inference). For example, `Vector:duplicateSize` ([`lib/container`][lib/container]) takes a single `#y`. Since `#y` is a function param, it can be inferred from the argument that gets passed, ... ...
近期下载者

相关文件


收藏者