Skip to content

Commit

Permalink
Machinery to allow distinguishing from missing field and null field
Browse files Browse the repository at this point in the history
Fixes #50
  • Loading branch information
AngheloAlf committed Feb 23, 2024
1 parent a60b31a commit 373edf2
Show file tree
Hide file tree
Showing 15 changed files with 299 additions and 101 deletions.
9 changes: 4 additions & 5 deletions docs/file_format/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ attribute. Check their specific documents for in-deep explanations.
```yaml
settings:
base_path: build
use_subalign: True
subalign: 32

segments:
Expand All @@ -27,7 +26,7 @@ segments:
- { path: asm/entry.o }

- name: boot
use_subalign: False
subalign: null
files:
- { path: src/boot/boot_main.o }
- { path: src/boot/dmadata.o }
Expand All @@ -47,9 +46,9 @@ This will force this segment to be put at this specific address.
Since the `boot` segment does not specify a fixed `vram` address then its
address will be the end vram address of the previous segment (`entry`).

The `boot` segment specified `use_subalign` to be `False`, so a`SUBALIGN`
directive should not be used for this segment. This means sections from every
file will be aligned using the alignment from the elf files.
The `boot` segment specified `subalign` to be `null`, so a `SUBALIGN` directive
should not be used for this segment. This means sections from every file will
be aligned using the alignment from the elf files.

The same sections of each file are put together in the order specified by the
`settings`. Since no order was specified in this example then the default order
Expand Down
2 changes: 1 addition & 1 deletion docs/file_format/file.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ segments:
### Valid values
Any valid path.
Any valid non-empty path.
## `kind`

Expand Down
35 changes: 7 additions & 28 deletions docs/file_format/segments.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ segments:
### Valid values
String.
Non empty string.
TODO: Impose rules for valid names?
Expand Down Expand Up @@ -70,35 +70,14 @@ Any unsigned integer.

`null`

## `use_subalign`

Toggle using the `SUBALIGN` directive on this segment.

This option overrides the global setting, see
[settings.md#use_subalign](settings.md#use_subalign) for more info.

### Example

```yaml
segments:
- name: boot
use_subalign: False
```

### Valid values

Boolean

### Default value

The value specified for [settings.md#use_subalign](settings.md#use_subalign)

## `subalign`

The value to use in the `SUBALIGN` directive for this segment.

The [`use_subalign`](#use_subalign) option controls if this directive is
emitted or not.
If `null` is specified then no `SUBALIGN` directive is used for this segment.

If an integer is used then the `SUBALIGN` will be emitted for this segment,
regarding the global setting.

This option overrides the global setting, see
[settings.md#subalign](settings.md#subalign) for more info.
Expand All @@ -108,12 +87,12 @@ This option overrides the global setting, see
```yaml
segments:
- name: main
subalign: 4
subalign: null
```

### Valid values

Positive integers
Positive integers or `null`.

### Default value

Expand Down
27 changes: 2 additions & 25 deletions docs/file_format/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,34 +120,11 @@ List of strings.
`[.sbss, .scommon, .bss, COMMON]`

## `use_subalign`

Toggle using `SUBALIGN` directives on the segments.

This option can be overriden per segment, see
[segments.md#use_subalign](segments.md#use_subalign) for more info.

### Example

```yaml
settings:
use_subalign: False
```

### Valid values

Boolean

### Default value

`True`

## `subalign`

The value to use in the `SUBALIGN` directives.

The [`use_subalign`](#use_subalign) option controls if this directive is
emitted or not.
If the value is `null` then disables using `SUBALIGN` directives.

This option can be overriden per segment, see
[segments.md#subalign](segments.md#subalign) for more info.
Expand All @@ -161,7 +138,7 @@ settings:

### Valid values

Positive integers
Positive integers or `null`.

### Default value

Expand Down
2 changes: 2 additions & 0 deletions slinky-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ fn main() {
let document =
Document::read_file(Path::new("test_case.yaml")).expect("Error while parsing input file");

// println!("settings {:#?}", document.settings);

let mut writer = LinkerWriter::new(&document.settings);
writer.begin_sections();
for segment in &document.segments {
Expand Down
73 changes: 73 additions & 0 deletions slinky/src/absent_nullable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* SPDX-FileCopyrightText: © 2024 decompals */
/* SPDX-License-Identifier: MIT */

use serde::{Deserialize, Deserializer};

use crate::SlinkyError;

// https://stackoverflow.com/a/44332837/6292472

#[derive(Debug, PartialEq, Default)]
pub(crate) enum AbsentNullable<T> {
#[default]
Absent,
Null,
Value(T),
}

impl<T> From<Option<T>> for AbsentNullable<T> {
fn from(opt: Option<T>) -> AbsentNullable<T> {
match opt {
Some(v) => AbsentNullable::Value(v),
None => AbsentNullable::Null,
}
}
}

impl<'de, T> Deserialize<'de> for AbsentNullable<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Option::deserialize(deserializer).map(Into::into)
}
}

impl<T> AbsentNullable<T> {
pub fn get_non_null<F>(self, name: &str, default: F) -> Result<T, SlinkyError>
where
F: FnOnce() -> T,
{
match self {
AbsentNullable::Absent => Ok(default()),
AbsentNullable::Null => Err(SlinkyError::NullValueOnNonNull {
name: name.to_string(),
}),
AbsentNullable::Value(v) => Ok(v),
}
}

pub fn get_non_null_no_default(self, name: &str) -> Result<Option<T>, SlinkyError> {
match self {
AbsentNullable::Absent => Ok(None),
AbsentNullable::Null => Err(SlinkyError::NullValueOnNonNull {
name: name.to_string(),
}),
AbsentNullable::Value(v) => Ok(Some(v)),
}
}

pub fn get_optional_nullable<F>(self, _name: &str, default: F) -> Result<Option<T>, SlinkyError>
where
F: FnOnce() -> Option<T>,
{
match self {
AbsentNullable::Absent => Ok(default()),
AbsentNullable::Null => Ok(None),
AbsentNullable::Value(v) => Ok(Some(v)),
}
}
}
46 changes: 29 additions & 17 deletions slinky/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use std::{fs, path::Path};

use serde::Deserialize;

use crate::{FileKind, Segment, Settings, SlinkyError};
use crate::{
absent_nullable::AbsentNullable, segment::SegmentSerial, settings::SettingsSerial, Segment,
Settings, SlinkyError,
};

#[derive(Deserialize, PartialEq, Debug)]
#[derive(PartialEq, Debug, Default)]
pub struct Document {
#[serde(default)]
pub settings: Settings,

pub segments: Vec<Segment>,
Expand All @@ -25,7 +27,7 @@ impl Document {
})
}
};
let mut document: Document = match serde_yaml::from_reader(f) {
let document_serial: DocumentSerial = match serde_yaml::from_reader(f) {
Ok(d) => d,
Err(e) => {
return Err(SlinkyError::FailedYamlParsing {
Expand All @@ -34,22 +36,32 @@ impl Document {
}
};

for segment in &mut document.segments {
segment
.use_subalign
.get_or_insert(document.settings.use_subalign);
segment.subalign.get_or_insert(document.settings.subalign);
Ok(document_serial.unserialize()?)
}
}

#[derive(Deserialize, PartialEq, Debug)]
pub(crate) struct DocumentSerial {
#[serde(default)]
pub settings: AbsentNullable<SettingsSerial>,

pub segments: Vec<SegmentSerial>,
}

impl DocumentSerial {
pub fn unserialize(self) -> Result<Document, SlinkyError> {
let mut ret = Document::default();

segment
.wildcard_sections
.get_or_insert(document.settings.wildcard_sections);
ret.settings = match self.settings.get_non_null_no_default("settings")? {
None => ret.settings,
Some(v) => v.unserialize()?,
};

for file in &mut segment.files {
// TODO: guess based on file extension
file.kind.get_or_insert(FileKind::Object);
}
ret.segments.reserve(self.segments.len());
for seg in self.segments {
ret.segments.push(seg.unserialize(&ret.settings)?);
}

Ok(document)
Ok(ret)
}
}
4 changes: 4 additions & 0 deletions slinky/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ pub enum SlinkyError {
FailedFileOpen { description: String },
#[error("Unable parse yaml: {description}")]
FailedYamlParsing { description: String },
#[error("Non-nullable attribute '{name}' was null")]
NullValueOnNonNull { name: String },
#[error("The attribute '{name}' should not be empty")]
EmptyValue { name: String },
}
33 changes: 29 additions & 4 deletions slinky/src/file_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,38 @@
/* SPDX-License-Identifier: MIT */

use serde::Deserialize;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

use crate::file_kind::FileKind;
use crate::{absent_nullable::AbsentNullable, file_kind::FileKind, Settings, SlinkyError};

#[derive(Deserialize, PartialEq, Debug)]
#[derive(PartialEq, Debug)]
pub struct FileInfo {
pub path: PathBuf,

pub kind: Option<FileKind>,
pub kind: FileKind,
}

#[derive(Deserialize, PartialEq, Debug)]
pub(crate) struct FileInfoSerial {
pub path: PathBuf,

#[serde(default)]
pub kind: AbsentNullable<FileKind>,
}

impl FileInfoSerial {
pub(crate) fn unserialize(self, _settings: &Settings) -> Result<FileInfo, SlinkyError> {
if self.path == Path::new("") {
return Err(SlinkyError::EmptyValue {
name: "path".to_string(),
});
}

let path = self.path;
let kind = self
.kind
.get_non_null("kind", || FileKind::from_path(&path))?;

Ok(FileInfo { path, kind })
}
}
15 changes: 15 additions & 0 deletions slinky/src/file_kind.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* SPDX-FileCopyrightText: © 2024 decompals */
/* SPDX-License-Identifier: MIT */

use std::path::Path;

use serde::Deserialize;

#[derive(Deserialize, PartialEq, Debug)]
Expand All @@ -9,3 +11,16 @@ pub enum FileKind {
Object,
Archive,
}

impl FileKind {
pub fn from_path(path: &Path) -> Self {
match path.extension() {
None => Self::Object,
Some(ext) => match ext.to_str() {
None => Self::Object,
Some("o") => Self::Object,
Some(&_) => Self::Object,
},
}
}
}
1 change: 1 addition & 0 deletions slinky/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* SPDX-FileCopyrightText: © 2024 decompals */
/* SPDX-License-Identifier: MIT */

mod absent_nullable;
mod error;

mod linker_symbols_style;
Expand Down
Loading

0 comments on commit 373edf2

Please sign in to comment.