Skip to content
This repository was archived by the owner on Jul 6, 2019. It is now read-only.

ioreg syntax extension #108

Merged
merged 9 commits into from
Aug 7, 2014
Merged
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
24 changes: 21 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,26 @@ compile_rust :core_crate, {
recompile_on: :triple,
}

# ioreg
compile_rust :ioreg_crate, {
source: 'ioreg/ioreg.rs'.in_root,
produce: 'ioreg/ioreg.rs'.in_root.as_rlib.in_build,
out_dir: true,
build_for: :host,
}

compile_rust :macro_ioreg, {
source: 'macro/ioreg.rs'.in_root,
deps: [:ioreg_crate],
produce: 'macro/ioreg.rs'.in_root.as_dylib.in_build,
out_dir: true,
build_for: :host,
}

# zinc crate
compile_rust :zinc_crate, {
source: 'main.rs'.in_source,
deps: [:core_crate, :rlibc_crate],
deps: [:core_crate, :rlibc_crate, :macro_ioreg],
produce: 'main.rs'.in_source.as_rlib.in_build,
out_dir: true,
recompile_on: [:triple, :platform],
Expand Down Expand Up @@ -96,8 +112,10 @@ desc "Build API documentation"
task build_docs: [:build_docs_html]

task build_docs_html: [] do |t|
['src/main.rs', 'platformtree/platformtree.rs'].each do |f|
sh ("rustdoc -w html -o build/doc " + f + ' ' + :config_flags.in_env.join(' '))
['src/main.rs', 'platformtree/platformtree.rs', 'ioreg/ioreg.rs'].each do |f|
build = Context.instance.build_dir
sh ("rustdoc -w html -o #{build}/doc -L #{build} " \
+ f + ' ' + :config_flags.in_env.join(' '))
end
end

Expand Down
203 changes: 203 additions & 0 deletions ioreg/builder/accessors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::ast;
use syntax::ast::P;
use syntax::codemap::DUMMY_SP;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::utils;
use super::super::node;

/// A visitor to build accessor functions for each register struct
pub struct BuildAccessors<'a, 'b, 'c> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to unify lifetimes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vladimir Pouzanov [email protected] writes:

+/// A visitor to build accessor functions for each register struct
+pub struct BuildAccessors<'a, 'b, 'c> {

Any reason not to unify lifetimes here?

I played around with these for quite a while to make the borrow checker
happy. That being said, things have changed substantially since then, so
perhaps they can now be unified. I'll have a look later.

builder: &'a mut Builder,
cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> node::RegVisitor for BuildAccessors<'a, 'b, 'c> {
fn visit_prim_reg(&mut self, path: &Vec<String>, reg: &node::Reg,
_width: node::RegWidth, fields: &Vec<node::Field>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just _?

let item = build_get_fn(self.cx, path, reg);
self.builder.push_item(item);

for field in fields.iter() {
match build_field_accessors(self.cx, path, reg, field) {
Some(item) => self.builder.push_item(item),
None => {}
}
}
}
}

impl<'a, 'b, 'c> BuildAccessors<'a, 'b, 'c> {
pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
-> BuildAccessors<'a, 'b, 'c> {
BuildAccessors {builder: builder, cx: cx}
}
}

fn build_field_accessors<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
reg: &node::Reg, field: &node::Field)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please offset the repeating lines at 4 spaces (relative to fn start) here and everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll admit that I'm not a huge fan of this aspect of the style guidelines as it makes it much less clear where the function's signature ends and the body begins. That being said, I've made the changes.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, the rust style guide is to align subsequent arguments with the first argument. https://github.com/rust-lang/rust-guidelines/blob/master/style/whitespace.md#line-wrapping (not sure if that's against the Zinc style guide or not)

fn frobnicate(a: Bar, b: Bar,
              c: Bar, d: Bar)
              -> Bar {
    ...
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking of it, I just don't like the "dangling" -> part, really. And I like how

fn func(arg1,
    arg2) -> Whatever {
  let first_line = 1;
}

makes a clear visual distinction on where the body starts. Let's move this into ML maybe? No sense to make a major restyling work because of that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and the same is actually in google c++ style guide so I don't know what's wrong with me :-) keep it as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@farcaller just to make sure we are on the same page, what style would you prefer here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep it as it is now. However, if you can fit everything in one line given that line starts with 4-space indent — that would be preferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright.

-> Option<P<ast::Item>>
{
let reg_ty: P<ast::Ty> =
cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

let items = match field.access {
node::ReadWrite => vec!(build_field_set_fn(cx, path, reg, field),
build_field_get_fn(cx, path, reg, field)),
node::ReadOnly => vec!(build_field_get_fn(cx, path, reg, field)),
node::WriteOnly => vec!(build_field_set_fn(cx, path, reg, field)),
node::SetToClear => vec!(build_field_clear_fn(cx, path, reg, field)),
};

let access_tag = match field.access {
node::ReadWrite => "read/write",
node::ReadOnly => "read-only",
node::WriteOnly => "write-only",
node::SetToClear => "set-to-clear",
};

let field_doc = match field.docstring {
Some(ref d) => {
let s = token::get_ident(d.node);
s.get().into_string()
},
None => "no documentation".into_string()
};
let docstring = format!("*[{}]* Field `{}`: {}",
access_tag,
field.name.node,
field_doc);
let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

quote_item!(cx,
$doc_attr
impl $reg_ty {
$items
}
)
}

fn build_get_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg)
-> P<ast::Item>
{
let reg_ty: P<ast::Ty> =
cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
let getter_ty = utils::getter_name(cx, path);

let docstring = format!("Fetch the value of the `{}` register",
reg.name.node);
let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

let item = quote_item!(cx,
impl $reg_ty {
$doc_attr
#[allow(dead_code)]
pub fn get(&'static self) -> $getter_ty {
$getter_ty::new(self)
}
}
);
item.unwrap()
}

fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
reg: &node::Reg, field: &node::Field)
-> P<ast::Method>
{
let fn_name =
cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
let field_ty: P<ast::Ty> =
cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
let setter_ty = utils::setter_name(cx, path);
if field.count.node == 1 {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self, new_value: $field_ty) -> $setter_ty {
let mut setter: $setter_ty = $setter_ty::new(self);
setter.$fn_name(new_value);
setter
}
)
} else {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self, idx: uint, new_value: $field_ty) -> $setter_ty {
let mut setter: $setter_ty = $setter_ty::new(self);
setter.$fn_name(idx, new_value);
setter
}
)
}
}

fn build_field_get_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
reg: &node::Reg, field: &node::Field)
-> P<ast::Method>
{
let fn_name = cx.ident_of(field.name.node.as_slice());
let field_ty: P<ast::Ty> =
cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
let getter_ty = utils::getter_name(cx, path);
if field.count.node == 1 {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self) -> $field_ty {
$getter_ty::new(self).$fn_name()
}
)
} else {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self, idx: uint) -> $field_ty {
$getter_ty::new(self).$fn_name(idx)
}
)
}
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
_reg: &node::Reg, field: &node::Field)
-> P<ast::Method>
{
let fn_name =
cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
let setter_ty = utils::setter_name(cx, path);
if field.count.node == 1 {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self) -> $setter_ty {
let mut setter: $setter_ty = $setter_ty::new(self);
setter.$fn_name();
setter
}
)
} else {
quote_method!(cx,
#[allow(dead_code, missing_doc)]
pub fn $fn_name(&'static self, idx: uint) -> $setter_ty {
let mut setter: $setter_ty = $setter_ty::new(self);
setter.$fn_name(idx);
setter
}
)
}
}
Loading