Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# [links-notation](https://github.com/link-foundation/links-notation) (languages: en • [ru](README.ru.md))

| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/js/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=js) | [![npm Version and Downloads count](https://img.shields.io/npm/v/links-notation?label=npm&style=flat)](https://www.npmjs.com/package/links-notation) | **[JavaScript](js/README.md)** |
|:-|-:|:-|
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/rust/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=rust) | [![Crates.io Version and Downloads count](https://img.shields.io/crates/v/links-notation?label=crates.io&style=flat)](https://crates.io/crates/links-notation) | **[Rust](rust/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/csharp/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=csharp) | [![NuGet Version and Downloads count](https://img.shields.io/nuget/v/Link.Foundation.Links.Notation?label=nuget&style=flat)](https://www.nuget.org/packages/Link.Foundation.Links.Notation) | **[C#](csharp/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/python/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=python) | [![PyPI Version and Downloads count](https://img.shields.io/pypi/v/links-notation?label=pypi&style=flat)](https://pypi.org/project/links-notation/) | **[Python](python/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/go/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=go) | [![Go Reference](https://pkg.go.dev/badge/github.com/link-foundation/links-notation/go.svg)](https://pkg.go.dev/github.com/link-foundation/links-notation/go) | **[Go](go/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/java/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=java) | [![Maven Central Version](https://img.shields.io/maven-central/v/io.github.link-foundation/links-notation?label=maven&style=flat)](https://central.sonatype.com/artifact/io.github.link-foundation/links-notation) | **[Java](java/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/js/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=js) | [![npm Version and Downloads count](https://img.shields.io/npm/v/links-notation?label=npm&style=flat)](https://www.npmjs.com/package/links-notation) | **[JavaScript](js/README.md)** |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------- |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/rust/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=rust) | [![Crates.io Version and Downloads count](https://img.shields.io/crates/v/links-notation?label=crates.io&style=flat)](https://crates.io/crates/links-notation) | **[Rust](rust/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/csharp/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=csharp) | [![NuGet Version and Downloads count](https://img.shields.io/nuget/v/Link.Foundation.Links.Notation?label=nuget&style=flat)](https://www.nuget.org/packages/Link.Foundation.Links.Notation) | **[C#](csharp/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/python/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=python) | [![PyPI Version and Downloads count](https://img.shields.io/pypi/v/links-notation?label=pypi&style=flat)](https://pypi.org/project/links-notation/) | **[Python](python/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/go/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=go) | [![Go Reference](https://pkg.go.dev/badge/github.com/link-foundation/links-notation/go.svg)](https://pkg.go.dev/github.com/link-foundation/links-notation/go) | **[Go](go/README.md)** |
| [![Actions Status](https://github.com/link-foundation/links-notation/workflows/java/badge.svg)](https://github.com/link-foundation/links-notation/actions?workflow=java) | [![Maven Central Version](https://img.shields.io/maven-central/v/io.github.link-foundation/links-notation?label=maven&style=flat)](https://central.sonatype.com/artifact/io.github.link-foundation/links-notation) | **[Java](java/README.md)** |

[![Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/link-foundation/links-notation)
[![Open in GitHub Codespaces](https://img.shields.io/badge/GitHub%20Codespaces-Open-181717?logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=link-foundation/links-notation)
Expand Down Expand Up @@ -38,7 +38,7 @@ var links = parser.Parse("papa (lovesMama: loves mama)");
### JavaScript

```javascript
import { Parser } from 'links-notation';
import { Parser } from "links-notation";
const parser = new Parser();
const links = parser.parse("papa (lovesMama: loves mama)");
```
Expand Down Expand Up @@ -123,7 +123,7 @@ This is equivalent to:
(3: papa loves mama)
```

So that means that *this* text is also links notation. So most of the
So that means that _this_ text is also links notation. So most of the
text in the world already may be parsed as links notation. That makes
links notation the most easy an natural/intuitive/native one.

Expand All @@ -134,7 +134,7 @@ structured data as links between ~~entities~~ references to links.
It's designed to be:

- **Natural**: Most text can already be parsed as links notation
- **Flexible**: Supports any number of references in each link
- **Flexible**: Supports any number of references in each link
- **Universal**: Can represent doublets, triplets, and N-tuples
- **Hierarchical**: Supports nested structures with indentation

Expand Down
160 changes: 160 additions & 0 deletions examples/js_streaming_parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env node

/**
* Example: Using StreamParser for incremental parsing in JavaScript
*
* This example demonstrates how to use the StreamParser to process
* Links Notation data incrementally, which is useful for:
* - Large files that don't fit in memory
* - Network streaming (e.g., TCP/HTTP streaming)
* - Real-time processing of incoming data
*/

import { StreamParser } from '../js/src/StreamParser.js';

console.log('=== JavaScript StreamParser Example ===\n');

// Example 1: Basic usage with event listeners
console.log('Example 1: Basic usage with event listeners');
console.log('-------------------------------------------');

const parser1 = new StreamParser();
let linkCount = 0;

parser1.on('link', (link) => {
linkCount++;
console.log(`Link #${linkCount}:`, link.toString());
});

parser1.on('error', (error) => {
console.error(`Error at line ${error.line}, col ${error.column}: ${error.message}`);
});

// Feed data incrementally (simulating network chunks)
parser1.write('papa (lovesMama: loves mama)\n');
parser1.write('son lovesMama\n');
parser1.write('daughter lovesMama\n');

const links1 = parser1.end();
console.log(`\nTotal links parsed: ${links1.length}\n`);

// Example 2: Processing data in very small chunks
console.log('Example 2: Processing data in small chunks');
console.log('-------------------------------------------');

const parser2 = new StreamParser();

parser2.on('link', (link) => {
console.log('Parsed:', link.toString());
});

// Simulate character-by-character streaming
const message = '(message: hello world)\n(status: ok)\n';
for (let i = 0; i < message.length; i++) {
parser2.write(message[i]);
}

const links2 = parser2.end();
console.log(`Total links: ${links2.length}\n`);

// Example 3: Handling multiline indented syntax
console.log('Example 3: Multiline indented syntax');
console.log('-------------------------------------');

const parser3 = new StreamParser();

parser3.on('link', (link) => {
console.log('Parsed link:', link.toString());
});

parser3.write('relationship:\n');
parser3.write(' papa\n');
parser3.write(' loves\n');
parser3.write(' mama\n');

parser3.end();
console.log();

// Example 4: Error handling
console.log('Example 4: Error handling with location info');
console.log('---------------------------------------------');

const parser4 = new StreamParser();

parser4.on('error', (error) => {
console.log('✓ Error caught successfully:');
console.log(` Message: ${error.message}`);
console.log(` Location: line ${error.line}, column ${error.column}`);
});

parser4.write('valid link here\n');
parser4.write('(unclosed parenthesis\n');

try {
parser4.end();
} catch (error) {
console.log(' (Error was also thrown as expected)\n');
}

// Example 5: Real-world use case - Simulating TCP stream
console.log('Example 5: Simulating TCP stream processing');
console.log('--------------------------------------------');

const parser5 = new StreamParser();
const receivedLinks = [];

parser5.on('link', (link) => {
receivedLinks.push(link);
console.log(`Received link: ${link.toString()}`);
});

// Simulate receiving network packets with partial data
const packets = [
'(user: alice',
') (action: ',
'login)\n(user',
': bob) (act',
'ion: logout)\n',
];

console.log('Processing packets...');
for (const packet of packets) {
parser5.write(packet);
}

parser5.end();
console.log(`\nProcessed ${receivedLinks.length} links from stream\n`);

// Example 6: Memory-efficient processing of large data
console.log('Example 6: Memory-efficient processing');
console.log('---------------------------------------');

const parser6 = new StreamParser();
let processedCount = 0;

parser6.on('link', (link) => {
// Process each link immediately without accumulating in memory
processedCount++;

// Simulate processing (e.g., database insert, validation, etc.)
if (processedCount % 1000 === 0) {
console.log(`Processed ${processedCount} links...`);
}
});

// Simulate processing a large file in chunks
const largeData = Array(5000)
.fill(0)
.map((_, i) => `(item: ${i})\n`)
.join('');

// Process in 1KB chunks
const chunkSize = 1024;
for (let i = 0; i < largeData.length; i += chunkSize) {
parser6.write(largeData.substring(i, i + chunkSize));
}

parser6.end();
console.log(`Final count: ${processedCount} links processed\n`);

console.log('=== All examples completed successfully! ===');
187 changes: 187 additions & 0 deletions examples/rust_streaming_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/// Example: Using StreamParser for incremental parsing in Rust
///
/// This example demonstrates how to use the StreamParser to process
/// Links Notation data incrementally, which is useful for:
/// - Large files that don't fit in memory
/// - Network streaming (e.g., TCP/HTTP streaming)
/// - Real-time processing of incoming data
///
/// To run this example:
/// ```
/// cargo run --example rust_streaming_parser
/// ```
use links_notation::StreamParser;
use std::sync::{Arc, Mutex};

fn main() {
println!("=== Rust StreamParser Example ===\n");

// Example 1: Basic usage with callbacks
println!("Example 1: Basic usage with callbacks");
println!("--------------------------------------");

let mut parser1 = StreamParser::new();
let link_count = Arc::new(Mutex::new(0));
let count_clone = Arc::clone(&link_count);

parser1.on_link(move |link| {
let mut count = count_clone.lock().unwrap();
*count += 1;
println!("Link #{}: {:?}", *count, link);
});

let error_received = Arc::new(Mutex::new(false));
let error_clone = Arc::clone(&error_received);

parser1.on_error(move |error| {
*error_clone.lock().unwrap() = true;
eprintln!("Error: {}", error);
});

// Feed data incrementally
parser1.write("papa (lovesMama: loves mama)\n").unwrap();
parser1.write("son lovesMama\n").unwrap();
parser1.write("daughter lovesMama\n").unwrap();

let links1 = parser1.finish().unwrap();
println!("\nTotal links parsed: {}\n", links1.len());

// Example 2: Processing data in small chunks
println!("Example 2: Processing data in small chunks");
println!("-------------------------------------------");

let mut parser2 = StreamParser::new();

parser2.on_link(|link| {
println!("Parsed: {:?}", link);
});

// Simulate character-by-character streaming
let message = "(message: hello world)\n(status: ok)\n";
for ch in message.chars() {
parser2.write(&ch.to_string()).unwrap();
}

let links2 = parser2.finish().unwrap();
println!("Total links: {}\n", links2.len());

// Example 3: Multiline indented syntax
println!("Example 3: Multiline indented syntax");
println!("-------------------------------------");

let mut parser3 = StreamParser::new();

parser3.on_link(|link| {
println!("Parsed link: {:?}", link);
});

parser3.write("relationship:\n").unwrap();
parser3.write(" papa\n").unwrap();
parser3.write(" loves\n").unwrap();
parser3.write(" mama\n").unwrap();

parser3.finish().unwrap();
println!();

// Example 4: Error handling with location info
println!("Example 4: Error handling with location info");
println!("---------------------------------------------");

let mut parser4 = StreamParser::new();

parser4.on_error(|error| {
println!("✓ Error caught successfully:");
println!(" Message: {}", error.message);
if let Some(ref loc) = error.location {
println!(" Location: line {}, column {}", loc.line, loc.column);
}
});

parser4.write("valid link here\n").unwrap();
parser4.write("(unclosed parenthesis\n").unwrap();

match parser4.finish() {
Ok(_) => println!("Unexpectedly succeeded"),
Err(e) => println!(" (Error was also returned as expected: {})\n", e),
}

// Example 5: Simulating TCP stream processing
println!("Example 5: Simulating TCP stream processing");
println!("--------------------------------------------");

let mut parser5 = StreamParser::new();
let received_links = Arc::new(Mutex::new(Vec::new()));
let links_clone = Arc::clone(&received_links);

parser5.on_link(move |link| {
let mut links = links_clone.lock().unwrap();
links.push(format!("{:?}", link));
println!("Received link: {:?}", link);
});

// Simulate receiving network packets with partial data
let packets = vec![
"(user: alice",
") (action: ",
"login)\n(user",
": bob) (act",
"ion: logout)\n",
];

println!("Processing packets...");
for packet in packets {
parser5.write(packet).unwrap();
}

parser5.finish().unwrap();
let final_count = received_links.lock().unwrap().len();
println!("\nProcessed {} links from stream\n", final_count);

// Example 6: Memory-efficient processing of large data
println!("Example 6: Memory-efficient processing");
println!("---------------------------------------");

let mut parser6 = StreamParser::new();
let processed_count = Arc::new(Mutex::new(0));
let count_clone = Arc::clone(&processed_count);

parser6.on_link(move |_link| {
let mut count = count_clone.lock().unwrap();
*count += 1;

// Simulate processing (e.g., database insert, validation, etc.)
if *count % 1000 == 0 {
println!("Processed {} links...", *count);
}
});

// Simulate processing a large file in chunks
let large_data: String = (0..5000)
.map(|i| format!("(item: {})\n", i))
.collect::<Vec<_>>()
.join("");

// Process in 1KB chunks
let chunk_size = 1024;
let bytes = large_data.as_bytes();
for chunk in bytes.chunks(chunk_size) {
if let Ok(chunk_str) = std::str::from_utf8(chunk) {
parser6.write(chunk_str).unwrap();
}
}

parser6.finish().unwrap();
let final_count = *processed_count.lock().unwrap();
println!("Final count: {} links processed\n", final_count);

// Example 7: Position tracking
println!("Example 7: Position tracking");
println!("-----------------------------");

let parser7 = StreamParser::new();
let pos = parser7.position();
println!("Initial position: line {}, column {}", pos.line, pos.column);
println!();

println!("=== All examples completed successfully! ===");
}
Loading