From 8dd6fb1766d31d82d807b054d2486f923619d131 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 8 Feb 2019 03:59:19 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 2 + LICENSE | 21 ++++++++ README.md | 82 +++++++++++++++++++++++++++++- base64/base64.v | 45 ++++++++++++++++ base64/base64_test.v | 8 +++ examples/concurrent_news_fetcher.v | 35 +++++++++++++ examples/generic_repository.v | 42 +++++++++++++++ examples/hello_world_gui.v | 42 +++++++++++++++ examples/users.v | 73 ++++++++++++++++++++++++++ 9 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 LICENSE create mode 100644 base64/base64.v create mode 100644 base64/base64_test.v create mode 100644 examples/concurrent_news_fetcher.v create mode 100644 examples/generic_repository.v create mode 100644 examples/hello_world_gui.v create mode 100644 examples/users.v diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..808377f09f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.v linguist-language=Go +website/* linguist-vendored diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..0fba9e4d7e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Alexander Medvednikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index dcd10679b7..5bca11e0d8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,81 @@ -# Official V repository +# The V Programming Language -V is going to be open-sourced in mid 2019. +V is going to be open-sourced in June 2019. Early access on April 15. + +https://vlang.io + +Documentation: https://vlang.io/docs + +Twitter: https://twitter.com/vlang_io + + +  + +## Fast compilation +V compiles 1.5 million lines of code per second per CPU core +``` +cd doom3/ +wc -l doom3.v # 458 713 +time v doom3.v # 0.5s +``` +[Compilation speed benchmark and comparison with other languages.](https://vlang.io/compilation_speed) + +## Safety +- No global state +- No null +- No undefined values +- Option types +- Generics +- Immutability by default +- Partially pure functions + +## C/C++ translation +V can translate your entire C/C++ project and offer you the safety, simplicity, and up to 200x compilation speed up. +``` +std::vector s; +s.push_back("V is "); +s.push_back("awesome"); +std::cout << s.size(); +``` +``` +s := []string +s << 'V is ' +s << 'awesome' +println(s.len) +``` +Read about translating Doom & Doom 3, LevelDB, SQLite (coming in March). + +## 400 KB compiler with zero dependencies +The entire V language and its standard library is less than 400 KB. You can build V in 0.3 seconds. + + +## Performance +- As fast as C +- Minimal amount of allocations +- Built-in serialization without reflection + +## Hot code reloading +Get your changes instantly without recompiling! + +Since you also don't have to waste time to get to the state you are working on after every compilation, this can save a lot of precious minutes of your development time. + +[Demonstration of hot code reloading.](https://volt-app.com/img/lang.webm) + +## Simple language for building maintainable programs +You can learn the entire language by going through the documentation in half an hour. + +Despite being simple, it gives a lot of power to the developer. Anything you can do in other languages, you can do in V. + +## REPL +``` + v + >> data := http.get('https://vlang.io/utc_now')? + >> data + '1551205308' +``` + +## Native cross platform UI library +Build native apps that look native. You no longer need to embed a browser to develop cross platform apps quickly. + +## Run everywhere +V can compile to (human readable) C, so you get the great platform support and optimization of gcc and Clang. diff --git a/base64/base64.v b/base64/base64.v new file mode 100644 index 0000000000..a1025749ab --- /dev/null +++ b/base64/base64.v @@ -0,0 +1,45 @@ +module base64 + +const ( + INDEX = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51] +) + +fn decode(data string) string { + p := data.str + len := data.len + mut pad := 0 + if len > 0 && (len % 4 != 0 || p[len - 1] == `=`) { + pad = 1 + } + L := ((len + 3) / 4 - pad) * 4 + str_len := L / 4 * 3 + pad + mut str := malloc(str_len + 2) + mut j := 0 + for i := 0; i < L; i += 4 { + n := (INDEX[p[i]] << 18) | (INDEX[p[i + 1]] << 12) | + (INDEX[p[i + 2]] << 6) | (INDEX[p[i + 3]]) + str[j] = n >> 16 + j++ + str[j] = n >> 8 & 0xff + j++ + str[j] = n & 0xff + j++ + } + if pad > 0 { + mut nn := (INDEX[p[L]] << 18) | (INDEX[p[L + 1]] << 12) + str[str_len - 1] = nn >> 16 + if len > L + 2 && p[L + 2] != `=` { + nn = nn | (INDEX[p[L + 2]] << 6) + str[str_len] = nn >> 8 & 0xff + } + } + str[str_len + 1] = `\0` + return string(str) +} + diff --git a/base64/base64_test.v b/base64/base64_test.v new file mode 100644 index 0000000000..720c47f651 --- /dev/null +++ b/base64/base64_test.v @@ -0,0 +1,8 @@ +import base64 + +fn test_decode() { + assert base64.decode('TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=') + == 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.' +} + + diff --git a/examples/concurrent_news_fetcher.v b/examples/concurrent_news_fetcher.v new file mode 100644 index 0000000000..faca945e15 --- /dev/null +++ b/examples/concurrent_news_fetcher.v @@ -0,0 +1,35 @@ +// Please share your thoughts, suggestions, questions, etc here: +// https://github.com/vlang-io/V/issues/3 +// I'm very interested in your feedback. +import http +import json +import runtime + +struct Story { + title string +} + +// Fetches top HN stories in 8 coroutines +fn main() { + resp := http.get('https://hacker-news.firebaseio.com/v0/topstories.json')? + ids := json.decode([]int, resp.body)? + mut cursor := 0 + for _ in 0..8 { + go fn() { + for { + lock { // Without this lock the program will not compile + if cursor >= ids.len { + break + } + id := ids[cursor] + cursor++ + } + url := 'https://hacker-news.firebaseio.com/v0/item/$id.json' + resp := http.get(url)? + story := json.decode(Story, resp.body)? + println(story.title) + } + }() + } + runtime.wait() // Waits for all coroutines to finish +} diff --git a/examples/generic_repository.v b/examples/generic_repository.v new file mode 100644 index 0000000000..7ac29a63fa --- /dev/null +++ b/examples/generic_repository.v @@ -0,0 +1,42 @@ +// Please share your thoughts, suggestions, questions, etc here: +// https://github.com/vlang-io/V/issues/3 + +// I'm very interested in your feedback. + +module main + +struct User { /* ... */ } +struct Post { /* ... */ } +struct DB { /* ... */ } + +struct Repo { + db DB +} + +// Generic code is notoriously verbose. To reduce clutter, V doesn't require you +// to add `` every time, since it already knows that Repo is a generic type. +fn new_repo(db DB) Repo { + return Repo{db: db} +} + +// This is a generic function. V will generate it for every type it's used with. +fn (r Repo) find_by_id(id int) T? { // `?` means the function returns an optional + table_name := T.name // in this example getting the name of the type gives us the table name + return r.db.query_one('select * from $table_name where id = ?', id) +} + +fn main() { + db := new_db() + users_repo := new_repo(db) + // I'm also considering passing the type as an argument + // users_repo := new_repo(User, db) + posts_repo := new_repo(db) + user := users_repo.find_by_id(1) or { + eprintln('User not found') + return + } + post := posts_repo.find_by_id(1) or { + eprintln('Post not found') + return + } +} diff --git a/examples/hello_world_gui.v b/examples/hello_world_gui.v new file mode 100644 index 0000000000..9dd8c59f32 --- /dev/null +++ b/examples/hello_world_gui.v @@ -0,0 +1,42 @@ +// Please share your thoughts, suggestions, questions, etc here: +// https://github.com/vlang-io/V/issues/3 + +// I'm very interested in your feedback. + +module main + +import ui // Native cross platform ui toolkit (uses Cocoa, win32, GTK+) + +// There are no globals, so we have to use a context struct +struct Context { + input ui.TextBox // this uses native controls (NSTextView on macOS, edit HWND on Windows) + names []string // let's log the names to demonstrate how arrays work +} + +fn main() { + wnd := ui.new_window(ui.WindowCfg{ // V has no default arguments and overloading. + width: 600 // All stdlib functions with many args use Cfg wrappers. + height: 300 + title: 'hello world' + }) + ctx := Context{ + input: ui.new_textbox(wnd) + // we don't need to initialize the names array, it's done automatically + } + ctx.input.set_placeholder('Enter your name') + btn := ui.new_button(wnd, 'Click me', ctx.btn_click) + for { + ui.wait_events() + } +} + +fn (ctx mut Context) btn_click() { + name := ctx.input.text() + ctx.input.hide() + println('current list of names: $ctx.names') // >> current list of names: [ "Bob", "Alex" ] + ui.alert('Hello, $name!') + if ctx.names.contains(name) { + ui.alert('I already greeted you ;)') + } + ctx.names << name +} diff --git a/examples/users.v b/examples/users.v new file mode 100644 index 0000000000..c7d68953ab --- /dev/null +++ b/examples/users.v @@ -0,0 +1,73 @@ +// Please share your thoughts, suggestions, questions, etc here: +// https://github.com/vlang-io/V/issues/3 + +// I'm very interested in your feedback. + +module main + +import json // V will automatically insert missing imports (like the goimports tool) +import http + +// Right now V requires all consts to be uppercase. +// I'm still not certain about this. +const API_URL = 'https://vlang.io/users.json' + +// V will generate json.encode and json.decode functions for this type since +// `json.decode([]User, ...)` is called later. This results in better +// performance, since reflection is not used. +struct User { + name string // V will automatically format and align your code. + age int // No need to use an additional tool. + is_registered bool +} + +fn main() { + // `http.get()` returns an optional string. + // V optionals combine the features of Rust's Option and Result. + // We must unwrap all optionals with `or`, otherwise V will complain. + s := http.get(API_URL) or { + // `err` is a reserved variable (not a global) that + // contains an error message if there is one + eprintln('Failed to fetch "users.json": $err') + // `or` blocks must end with `return`, `break`, or `continue` + return + } + // Types can be passed as arguments + users := json.decode([]User, s) or { + eprintln('Failed to parse users.json') + return + } + // Encoding JSON doesn't require a type, since V knows what type + // the variable `users` has + println(json.encode(users)) + // Please note the difference between V and Go: + // when there's only one variable, it's a value, not an index. + for user in users { + println('$user.name: $user.age') + } + // `for` loop has an alternative form when an index is required: + for i, user in users { + println('$i) $user') + if !user.can_register() { + // V allows both ' and " to denote strings. + // However, for consistency V will replace " with ' + // unless the string contains an apostrophe. + println("Can't register") + } + } +} + +// The method declaration is the same as in Go. +// There is one big difference. Here `u` can be either passed by value (User) +// or by reference (&User). The compiler will make the right decision +// depending on the size of the User struct. You no longer have to remember +// which one to use. It works here because `u` can't be modified (it's not +// marked as `mut`). +fn (u User) can_register() bool { + return u.age >= 16 +} + +// Here `u` can be modified and it will always be a reference. +fn (u mut User) register() { + u.is_registered = true +}