Skip to content

Commit

Permalink
Merge pull request #845 from nevalang/fix-lsp-compiler-errors
Browse files Browse the repository at this point in the history
Fix LSP compiler errors
  • Loading branch information
emil14 authored Jan 23, 2025
2 parents dd02589 + 4833898 commit bc412b9
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 53 deletions.
14 changes: 14 additions & 0 deletions .vscode/bookmarks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"files": [
{
"path": "internal/compiler/analyzer/nodes.go",
"bookmarks": [
{
"line": 213,
"column": 2,
"label": ""
}
]
}
]
}
125 changes: 92 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@
</p>

<div align="center">
Next-generation programming language that solves programmer's problems
Next-generation programming language that solves programmers' problems
</div>
<br/>

![tests](https://github.com/nevalang/neva/actions/workflows/test.yml/badge.svg?branch=main) ![lint](https://github.com/nevalang/neva/actions/workflows/lint.yml/badge.svg?branch=main) [![go report](https://goreportcard.com/badge/github.com/nevalang/neva)](https://goreportcard.com/report/github.com/nevalang/neva) [![Discord](https://img.shields.io/discord/1094102475927203921?logo=discord&logoColor=white&color=5865F2)](https://discord.gg/dmXbC79UuH) [![ChatGPT](https://img.shields.io/badge/Nevalang_AI-74aa9c?logo=openai&logoColor=white)](https://chatgpt.com/g/g-RhZn00MXU-nevalang-expert) ![OS](https://img.shields.io/badge/os-windows%20%7C%20macos%20%7C%20linux-lightgrey?logo=linux&logoColor=white) ![Go](https://img.shields.io/badge/v1.23-00ADD8?logo=go&logoColor=white) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

[**Documentation**](./docs/README.md)
| [**Examples**](./examples/)
| [**Community**](#-community)
| [**Releases**](https://github.com/nevalang/neva/releases)
| [**Contributing**](./CONTRIBUTING.md)
| [**Architecture**](./ARCHITECTURE.md)

![tests](https://github.com/nevalang/neva/actions/workflows/test.yml/badge.svg?branch=main) ![lint](https://github.com/nevalang/neva/actions/workflows/lint.yml/badge.svg?branch=main)

</div>

> **⚠️ WARNING**: This project is under active development and not yet production-ready!
## 🤔 What Is Nevalang?

Nevalang is a new kind of programming language where instead of writing step-by-step instructions you create **networks** where data flows between **nodes** as **immutable messages** and everything runs **in parallel by default**. After **type-checking**, your program is compiled into **machine code** and can be distributed as a **single executable** with zero dependencies.
Expand All @@ -34,7 +36,15 @@ Combined with built-in **stream processing** support and features like **advance

Future updates will include **visual programming** and **Go interoperability** to allow gradual adoption and leverage existing ecosystem.

> ⚠️ This project is under active development and not yet production-ready.
### Why Yet Another Programming Language?

We created Nevalang because we saw a gap in the programming language landscape:

1. **Visual Programming Done Right** - While there are many visual programming tools, they're usually limited to specific domains or lack the power of traditional programming. Nevalang is designed from the ground up to be a hybrid visual/text-based programming environment.
2. **Simple Parallel Programming** - Most languages treat concurrency as an advanced feature, making it complex and error-prone. In Nevalang, parallelism is the default, and the language design prevents common issues like data races.
3. **Modern Developer Experience** - We combine the best ideas from modern languages with dataflow programming to create a unique development experience focused on productivity.

Finally, we believe exploring new programming paradigms is valuable for the entire programming community, even if only to learn what works and what doesn't.

## 👋 Hello, World!

Expand All @@ -48,30 +58,30 @@ def Main(start any) (stop any) {
}
```

Whats happening here:
What's happening here:

- `import { fmt }` loads the `fmt` package for printing
- `def Main` defines the main component with input port `start` and output port `stop`
- `:start -> Hello, World! -> println -> :stop` defines a connection that sends `Hello, World!` string to the `println` printer-node and then terminates the program
- `def Main` defines the main component with input port `start` and output port `stop` of type `any` (it's safe since it's only used as a signal)
- `:start -> 'Hello, World!' -> println -> :stop` defines a connection that sends the string to `println` when program starts and terminates after printing (runtime sends a message to `Main:start` at startup and waits for `Main:stop` to terminate)

## 🔥 Features

- 📨 **Dataflow Programming** - Write programs as message-passing graphs
- 🔀 **Implicit Parallelism** - Everything is parallel by default, no async-await/threads/goroutines/etc.
- 🛡️ **Strong Static Typing** - Robust type system with generics and pattern-matching
- 🚀 **Machine Code Compilation** - Compile for any Go-supported platform, including WASM
- ⚡️ **Stream Processing** - Handle real-time data with streams as first class citizens
- 🧯 **Advanced Error Handling** - Errors as values with `?` operator to avoid boilerplate
- 🧩 **Functional Patterns** - Immutability and higher-order components
- 🔌 **Dependency Injection** - Modularity with interfaces and DI
- 🪶 **Minimal Core** - Simple language with limited abstractions
- 📦 **Package Manager** - Publish packages by pushing a git-tag
- ♻️ **Garbage Collection** - Automatic memory management using Go's low-latency GC
- 🌈 **Visual Programming** (WIP): Edit programs as visual graphs
- 🔄 **Go Interoperability** (WIP): Call Go from Neva and Neva from Go
- 🕵 **NextGen Debugging** (WIP): Observe execution in realtime and intercept messages on the fly

## 🧐 Why Nevalang?
- **Dataflow Programming** - Write programs as message-passing graphs
- **Implicit Parallelism** - Everything is parallel by default, no async-await/threads/goroutines/etc.
- **Strong Static Typing** - Robust type system with generics and pattern-matching
- **Machine Code Compilation** - Compile for any Go-supported platform, including WASM
- **Stream Processing** - Handle real-time data with streams as first class citizens
- **Advanced Error Handling** - Errors as values with `?` operator to avoid boilerplate
- **Functional Patterns** - Immutability and higher-order components
- **Dependency Injection** - Modularity with interfaces and DI
- **Minimal Core** - Simple language with limited abstractions
- **Package Manager** - Publish packages by pushing a git-tag
- **Garbage Collection** - Automatic memory management using Go's low-latency GC
- **Visual Programming** (WIP): Edit programs as visual graphs
- **Go Interoperability** (WIP): Call Go from Neva and Neva from Go
- **NextGen Debugging** (WIP): Observe execution in realtime and intercept messages on the fly

## 🧐 Why Use Nevalang?

Let's compare Nevalang with Go. We could compare it to any language but Go is a simple reference since Nevalang is written in Go.

Expand All @@ -88,32 +98,81 @@ Let's compare Nevalang with Go. We could compare it to any language but Go is a
| **Dependency Injection** | Built-in - any component with dependency expects injection | Manual - programmer must create constructor function that takes dependencies |
| **Stream Processing** | Native support with components like `Map/Filter/Reduce` | Programmer must manually implement dataflow patterns with goroutines and channels |

## 📢 Community
## 🏭 Architecture

As you can see, this is quite an ambitious project. Typically, such projects are backed by companies, but Nevalang is maintained by a very small group of enthusiasts. Your support by joining us will show interest and motivate us to continue.
> This is a high-level overview. For a more detailed overview of the architecture, please see [ARCHITECTURE.md](./ARCHITECTURE.md)
- [Discord](https://discord.gg/dmXbC79UuH)
- [Reddit](https://www.reddit.com/r/nevalang/)
- [Telegram group](https://t.me/+H1kRClL8ppI1MWJi)
<div align="center">

### 🙏 Support
```mermaid
flowchart LR
source_code-->compiler-->|go_code| go_compiler
Please **give us a star ⭐️** to increase our chances of getting into GitHub trends - the more attention Nevalang gets, the higher our chances of actually making a difference.
subgraph compiler
parser-->analyzer-->backend
end
go_compiler-->machine_code
go_compiler-->wasm
```

</div>

Nevalang compiles to dependency-free, human-readable Go code that uses goroutines and channels for message-passing with parallelism. The Go compiler then produces optimized platform-specific code for any supported platform. This approach gives our programs access to Go's production-grade runtime with an advanced scheduler, garbage collector, and battle-tested standard library. We stand on the shoulders of giants.

## ⭐️ Star History

<p align="center">
<img src="./assets/animations/github_star.gif" alt="GitHub Star">
<a href="https://star-history.com/#nevalang/neva&Timeline">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=nevalang/neva&type=Timeline&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=nevalang/neva&type=Timeline" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=nevalang/neva&type=Timeline" />
</picture>
</a>
</p>

## 💭 What's Next?

> ℹ️ We take development seriously but have limited time to keep everything current. Feel free to reach out on our social platforms with any questions!
- [Documentation](./docs/README.md) - Install and learn the language basics
- [Examples](./examples/) - Learn the language by small programs

> Please keep in mind that these resources might not be ready or may be outdated due to the current state of the project. However, rest assured that we take development seriously. We simply don't have enough time to keep everything up to date all the time. Please don't feel intimidated and contact us on our social platforms if you have any questions. We welcome _any_ feedback, no matter what.
### Community

## 🤝 Contributing
This is an ambitious project maintained by a small group of enthusiasts. Your support by **joining us** will show interest and motivate us to continue.

[![Discord](https://img.shields.io/badge/Discord-7289DA?logo=discord&logoColor=white)](https://discord.gg/dmXbC79UuH)
[![Telegram](https://img.shields.io/badge/Telegram-26A5E4?logo=telegram&logoColor=white)](https://t.me/+H1kRClL8ppI1MWJi)
[![Reddit](https://img.shields.io/badge/Reddit-FF4500?logo=reddit&logoColor=white)](https://www.reddit.com/r/nevalang/)
[![Twitter](https://img.shields.io/badge/Twitter-000000?logo=x&logoColor=white)](https://x.com/neva_language)

### Contributing

1. See [contributing](./CONTRIBUTING.md) and [architecture](./ARCHITECTURE.md)
2. Check out [roadmap](https://github.com/nevalang/neva/milestones?direction=asc&sort=due_date&state=open) and [kanban-board](https://github.com/orgs/nevalang/projects/2/views/3?filterQuery=)
3. Also please read our [CoC](./CODE_OF_CONDUCT.md)
4. Join [discord server](https://discord.gg/dmXbC79UuH)

### Support

Please **give us a star ⭐️** to increase our chances of getting into GitHub trends - the more attention Nevalang gets, the higher our chances of actually making a difference.

<p align="center">
<img src="./assets/animations/github_star.gif" alt="GitHub Star">
</p>

Please **share this project** with your friends! Every share helps us reach more developers and grow our community. The more developers we reach, the more likely we are to build something truly revolutionary together. 🚀

<div align="center" style="display:grid;place-items:center;">

[![share on x](https://img.shields.io/badge/share-000000?logo=x&logoColor=white)](https://x.com/intent/tweet?text=Check%20out%20Nevalang%20on%20GitHub:%20https://github.com/nevalang/neva%20%23Programming%20%23DataFlow%20%23Concurrency)
[![share on facebook](https://img.shields.io/badge/share-1877F2?logo=facebook&logoColor=white)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/nevalang/neva)
[![share on reddit](https://img.shields.io/badge/share-FF4500?logo=reddit&logoColor=white)](https://www.reddit.com/submit?title=Check%20out%20Nevalang%20on%20GitHub:%20https://github.com/nevalang/neva)
[![share on telegram](https://img.shields.io/badge/share-0088CC?logo=telegram&logoColor=white)](https://t.me/share/url?url=https://github.com/nevalang/neva&text=Check%20out%20Nevalang%20on%20GitHub)
[![share on whatsapp](https://img.shields.io/badge/share-25D366?logo=whatsapp&logoColor=white)](https://wa.me/?text=Check%20out%20Nevalang%20on%20GitHub:%20https://github.com/nevalang/neva)
[![share on hackernews](https://img.shields.io/badge/share-F0652F?logo=ycombinator&logoColor=white)](https://news.ycombinator.com/submitlink?u=https://github.com/nevalang/neva&t=Nevalang:%20Next-generation%20programming%20language%20with%20implicit%20parallelism)
[![share on linkedin](https://img.shields.io/badge/linkedin-share-0A66C2?logo=linkedin&logoColor=white)](https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/nevalang/neva)

</div>
17 changes: 15 additions & 2 deletions cmd/lsp/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"path/filepath"
"strings"

"github.com/tliron/commonlog"

"github.com/nevalang/neva/internal/builder"
"github.com/nevalang/neva/internal/compiler"
"github.com/nevalang/neva/internal/compiler/analyzer"
Expand All @@ -15,6 +17,7 @@ import (
type Indexer struct {
fe compiler.Frontend
analyzer analyzer.Analyzer
logger commonlog.Logger
}

func (i Indexer) FullScan(
Expand All @@ -26,14 +29,19 @@ func (i Indexer) FullScan(
return src.Build{}, false, err
}

// if nevalang module is found, but it's not part of the workspace
if isParentPath(workspacePath, feResult.Path) {
i.logger.Debug(
"nevalang module found but not part of workspace",
"path", feResult.Path, "workspacePath", workspacePath,
)
return src.Build{}, false, nil
}

i.logger.Debug("nevalang module found in workspace", "path", feResult.Path)

aBuild, err := i.analyzer.AnalyzeBuild(feResult.ParsedBuild)
if err != nil {
return src.Build{}, false, err
return src.Build{}, true, err.Unwrap() // use only deepest compiler error for now
}

return aBuild, true, nil
Expand All @@ -45,6 +53,9 @@ func isParentPath(parent, child string) bool {

rel, err := filepath.Rel(parent, child)
if err != nil {
panic(err)
}
if rel == "." {
return false
}

Expand All @@ -55,9 +66,11 @@ func New(
builder builder.Builder,
parser parser.Parser,
analyzer analyzer.Analyzer,
logger commonlog.Logger,
) Indexer {
return Indexer{
fe: compiler.NewFrontend(builder, parser),
analyzer: analyzer,
logger: logger,
}
}
9 changes: 7 additions & 2 deletions cmd/lsp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ func main() {
isDebug := flag.Bool("debug", false, "-debug")
flag.Parse()

commonlog.Configure(1, nil)
loglvl := 1
if *isDebug {
loglvl = 2
}

commonlog.Configure(loglvl, nil)
logger := commonlog.GetLoggerf("%s.server", serverName)

p := parser.New()
Expand All @@ -31,7 +36,7 @@ func main() {
resolver := typesystem.MustNewResolver(typesystem.Validator{}, checker, terminator)
builder := builder.MustNew(p)

indexer := indexer.New(builder, p, analyzer.MustNew(resolver))
indexer := indexer.New(builder, p, analyzer.MustNew(resolver), logger)

handler := lspServer.BuildHandler(logger, serverName, indexer)

Expand Down
27 changes: 13 additions & 14 deletions cmd/lsp/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ type Server struct {
// indexAndNotifyProblems does full scan of the workspace
// and sends diagnostics if there are any problems
func (s *Server) indexAndNotifyProblems(notify glsp.NotifyFunc) error {
build, found, proplems := s.indexer.FullScan(
build, found, compilerErr := s.indexer.FullScan(
context.Background(),
s.workspacePath,
)

if !found {
return nil
}
Expand All @@ -49,7 +48,7 @@ func (s *Server) indexAndNotifyProblems(notify glsp.NotifyFunc) error {
s.index = &build
s.indexMutex.Unlock()

if proplems == nil {
if compilerErr == nil {
// clear problems
s.problemsMutex.Lock()
for uri := range s.problemFiles {
Expand All @@ -69,19 +68,22 @@ func (s *Server) indexAndNotifyProblems(notify glsp.NotifyFunc) error {

// remember problem and send diagnostic
s.problemsMutex.Lock()
uri := filepath.Join(s.workspacePath, proplems.Meta.Location.String())
uri := filepath.Join(s.workspacePath, compilerErr.Meta.Location.String()) // we assume compilerErr is deepest child (for now)
s.problemFiles[uri] = struct{}{}
notify(
protocol.ServerTextDocumentPublishDiagnostics,
s.createDiagnostics(*proplems, uri),
s.createDiagnostics(*compilerErr, uri),
)
s.logger.Info("diagnostic sent:", "err", proplems)
s.logger.Info("diagnostic sent:", "err", compilerErr)
s.problemsMutex.Unlock()

return nil
}

func (s *Server) createDiagnostics(compilerErr compiler.Error, uri string) protocol.PublishDiagnosticsParams {
func (s *Server) createDiagnostics(
compilerErr compiler.Error, // deepest child (for now) compiler error
uri string,
) protocol.PublishDiagnosticsParams {
var startStopRange protocol.Range
if compilerErr.Meta != nil {
// If stop is 0 0, set it to the same as start but with character incremented by 1
Expand All @@ -106,17 +108,14 @@ func (s *Server) createDiagnostics(compilerErr compiler.Error, uri string) proto
startStopRange.End.Line--
}

source := "neva"
severity := protocol.DiagnosticSeverityError

return protocol.PublishDiagnosticsParams{
URI: uri,
URI: uri, // uri must be full path to the file, make sure all compiler errors include full location
Diagnostics: []protocol.Diagnostic{
{
Range: startStopRange,
Severity: &severity,
Source: &source,
Message: compilerErr.Error(),
Severity: compiler.Pointer(protocol.DiagnosticSeverityError),
Source: compiler.Pointer("compiler"),
Message: compilerErr.Message, // we don't use Error() because it will duplicate location
Data: time.Now(),
},
},
Expand Down
4 changes: 2 additions & 2 deletions internal/compiler/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (e Error) Wrap(child *Error) *Error {
return &e
}

func (e Error) unwrap() *Error {
func (e Error) Unwrap() *Error {
for e.child != nil {
e = *e.child
}
Expand All @@ -28,7 +28,7 @@ func (e Error) unwrap() *Error {
func (e *Error) Error() string {
var s string

current := e.unwrap()
current := e.Unwrap()
hasMeta := current.Meta != nil

if hasMeta {
Expand Down
1 change: 1 addition & 0 deletions internal/compiler/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
)

// Pointer allows to avoid creating of temporary variables just to take pointers.
// TODO move to pkg/utils (or something like that)
func Pointer[T any](v T) *T {
return &v
}
Expand Down

0 comments on commit bc412b9

Please sign in to comment.